无法将X类型转换为T.泛型类中的泛型委托

问题描述 投票:0回答:1

请考虑以下代码:

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
}
c# generics delegates
1个回答
3
投票

T可能是一种来自Foo的类型,在这种情况下,将new Foo()传递给SomeDelegate<T>是不安全的。代表可能会尝试访问T上不存在的Foo成员。

你的第一个解决方法有效,但你可能会发现你的代表在解决方法之前无法做到所有事情,因为它现在需要一个Foo,而不是T

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

© www.soinside.com 2019 - 2024. All rights reserved.