考虑以下代码:
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的答案和评论:
添加一个类Moo => class Moo{}
,该类不是从Foo继承的,这是因为我的工作可能会导致运行时异常:
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
}
答案 0 :(得分:3)
T
可以是从Foo
派生的类型,在这种情况下,将new Foo()
传递到SomeDelegate<T>
是不安全的。委托可能尝试访问T
上不存在的Foo
成员。
您的第一个解决方法可行,但是您可能会发现委托人无法做解决该问题之前可以做的所有事情,因为它现在需要Foo
,而不是T
。
第二种解决方法可能会导致运行时异常。