请考虑以下代码:
delegate void SomeDelegate<in T>(T foo) where T : Foo;
class Foo { }
class SomeGenericClass<T> where T:Foo
{
private readonly SomeDelegate<T> _action = _ => Console.WriteLine("Foo");
public void DoStuff()=> _action(new Foo()); //here is the compiler error
}
代码是不言自明的,我有这个空的Foo类。然后我使用泛型约束定义泛型委托,以便type参数始终为Foo。然后我们有一个简单的泛型类,其约束与委托相同,在其中我们有一个泛型委托字段。 DoStuff调用此委托并传递Foo的新实例。
为什么这不编译?我的意思是,我知道为什么,编译器告诉我:
CS1503参数1:无法从'ConsoleForSimpleTests.Program.Foo'转换为'T'
问题是:为什么编译器在定义了泛型约束的情况下无法将Foo转换为T?为什么这里需要明确的演员表?
假设我添加以下类:class Boo:Foo { }
我可以通过两种方式使事情发挥作用:
第一:我们将泛型委托字段明确地声明为Foo
。在这种情况下,我甚至不需要SomeGenericClass
中的泛型类型参数
class SomeGenericClass<T> where T:Foo
{
private readonly SomeDelegate<Foo> _action = _ => Console.WriteLine("Foo");
public void DoStuff()
{
_action(new Foo());
_action(new Boo());
}
}
第二:我们保留T
,但我总是首先转向基类,然后转向T(直接转换为T不会为派生类编译)
class SomeGenericClass<T> where T:Foo
{
private readonly SomeDelegate<T> _action = _ => Console.WriteLine("Foo");
public void DoStuff()
{
_action((T)new Foo());
_action((T)(Foo)new Boo());
}
}
假设我将DoStuff
更改为:
public void DoStuff(T foo)
{
_action(foo);
}
测试:
var genericInstance = new SomeGenericClass<Foo>();
var foo = new Foo();
var boo = new Boo();
genericInstance.DoStuff(foo);
genericInstance.DoStuff(boo);
一切都很好;在DoStuff
中直接添加这些实例有什么区别?
public void DoStuff(T foo)
{
_action(foo);
_action(new Foo()); //does not compile
}
关于@Rawling的答案和评论:
添加一个不继承自Foo的类Moo => class Moo{}
,关于我的工作可能会导致运行时异常的事实:
public void DoStuff(T foo)
{
_action(foo);
_action((T)new Foo());
_action((T)(Foo)new Boo());
_action((T)(Foo)new Moo()); //this does not even compile
}
T
可能是一种来自Foo
的类型,在这种情况下,将new Foo()
传递给SomeDelegate<T>
是不安全的。代表可能会尝试访问T
上不存在的Foo
成员。
你的第一个解决方法有效,但你可能会发现你的代表在解决方法之前无法做到所有事情,因为它现在需要一个Foo
,而不是T
。
您的第二个解决方法可能会导致运行时异常。