2012-10-30 77 views
1

我正在努力如何正确使用C#泛型。具体来说,我想有一个方法将Generic Type作为参数,并根据Generic的类型做不同的事情。但是,我不能“贬低”泛型。看下面的例子。如何向下转换泛型类型的实例?

编译器抱怨演员表(Bar<Foo>)说“无法将类型Bar<T>转换为Bar<Foo>”。但是在运行时,因为我已经检查过类型,所以转换是OK的。

public class Foo { } 

public class Bar<T> { } 

// wraps a Bar of generic type Foo 
public class FooBar<T> where T : Foo 
{ 

    Bar<T> bar; 

    public FooBar(Bar<T> bar) 
    { 
     this.bar = bar; 
    } 

} 

public class Thing 
{ 
    public object getTheRightType<T>(Bar<T> bar) 
    { 
     if (typeof(T) == typeof(Foo)) 
     { 
      return new FooBar<Foo>((Bar<Foo>) bar); // won't compile cast 
     } 
     else 
     { 
      return bar; 
     } 
    } 
} 
+1

请问,如果你去'返回新FooBar的(酒吧,酒吧)'工作? – IronMan84

+0

使用泛型的一个优点是类型安全,但是通过返回'object'而不是更具体的类型来丢失一些类型安全。泛型的另一个优点是相同的代码可以用于多种类型,但是通过根据参数的类型分支实现来丢失一些优势。我不知道真正的程序是什么样的,但也许这些是一个指标,说明有一个更好的程序结构可能。 getTheRightType函数的目的是什么?结果如何使用? – Mike

+0

好点Mike。以上只是一个从真实代码中抽象出来的简单例子。真正的代码涉及电子表格结构和类工作表其中I和F是不同的数据结构类型。基于I和F的运行时类型,工作表的显示方式不同。我应该花更多时间处理模式并尝试改进程序结构。但是,最后期限,最后期限... –

回答

7

编译器无法知道Bar<T>可强制转换为Bar<Foo>在这种情况下,因为它通常不是真的。你必须在之间引入强制转换为object“欺骗”:

return new FooBar<Foo>((Bar<Foo>)(object) bar); 
+0

真正的推理曾经由Eric Lippert解释过。这有点复杂。毕竟编译器可以像你的例子那样发出代码。原则上没有任何反对意见。 – usr

+0

@usr,是的,我记得在Eric的博客上读到类似的内容,但我找不到确切的链接... –

+1

谢谢!我永远不会猜到这会起作用。我习惯于Java,在编译时你可以做downcast,但如果转换失败,在运行时会得到一个异常。 –

2

这应该做的伎俩,你将不必强制转换为object第一。

public class Thing 
{ 
    public object getTheRightType<T>(Bar<T> bar) 
    { 
     if (typeof(T) == typeof(Foo)) 
     { 
      return new FooBar<Foo>(bar as Bar<Foo>); // will compile cast 
     } 
     else 
     { 
      return bar; 
     } 
    } 
} 
+0

只要我在函数定义中添加T:class约束,这对我有用。 – Josh