无法将X类型转换为T。泛型类

时间:2018-06-21 22:45:45

标签: c# generics delegates

考虑以下代码:

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
}

1 个答案:

答案 0 :(得分:3)

T可以是从Foo派生的类型,在这种情况下,将new Foo()传递到SomeDelegate<T>是不安全的。委托可能尝试访问T上不存在的Foo成员。

您的第一个解决方法可行,但是您可能会发现委托人无法做解决该问题之前可以做的所有事情,因为它现在需要Foo,而不是T

第二种解决方法可能会导致运行时异常。