委托“错误的返回类型”

本文关键字:返回类型 错误 委托 | 更新日期: 2023-09-27 18:31:39

一方面,我有以下代表:

public delegate IBar FooDelegate(string str);
public delegate IBar FooDelegateWithRef(string str, IBar someBar);

另一方面,我有一个泛型类:

public class MyBaseClass
    where T : IBar, new()
{
    public FooDelegate myFunc;
    public FooDelegateWithRef myFuncWithRef;
}
public class MyClass<T> : MyBaseClass
    where T : IBar, new()
{
    public MyClass()
    {
        myFunc = Foo; //"Wrong return type"
        myFuncWithRef = FooWithRef; //"No overload...matches delegate"
    }
    public T Foo(string){ ... }
    public T FooWithRef(string, IBar){ ... }
}

我的问题是当我执行以下操作时:

FooDelegate fooRef = MyClassInstance.Foo;

我收到"错误的返回类型"错误。我知道委托签名必须与方法签名匹配,但是既然泛型中的"where"指令实际上明确指定了 T IBar,为什么它不起作用?

所以两个问题合二为一: - 为什么编译器拒绝考虑方法签名是否匹配? - 更重要的是,我怎样才能做到这一点?我更喜欢委托友好的解决方案,而不是出于约定原因使用 Func。

注意:我试图四处寻找答案,但我可能对这个问题的措辞有错误的措辞,所以如果之前已经回答过这个问题,请随时打我的脸。

编辑:正如@Jonathon Chase指出的那样,我的示例代码并没有完全包装问题。可以在此处找到一个非工作示例。编辑了上面的代码以反映问题。

编辑2:所有答案对我来说非常有用,非常感谢您的时间。如果可以的话,我会检查所有三个!

委托“错误的返回类型”

"错误的返回类型"错误是因为方差不支持值类型。 因此,实现IBarclass可以转换,而实现struct则不会:

class RefTypeBar : IBar {}
struct ValueTypeBar : IBar {}
FooDelegate f1 = new MyClass<RefTypeBar>().Foo;  // This works
FooDelegate f2 = new MyClass<ValueTypeBar().Foo; // Fails - wrong return type

错误是在MyClass<T>内部生成的,因为T可能是struct,因此编译器不能保证该Foo可以分配FooDelegate。 如果将class约束添加到MyClass<T>则代码将编译。

public class MyClass<T> : MyBaseClass where T : class, IBar, new()
这里的例子

一定还有其他事情。我目前能够编译并运行以下示例并收到预期的结果:

public class Program
{
    public static void Main()
    {
        var x = new MyClass<Bar>();
        FooDelegate test = x.Foo;
        test("Do It");
    }
    public delegate IBar FooDelegate(string str);
    public interface IBar { }
    public class Bar : IBar { }
    public class MyClass<T> where T : IBar, new()
    {
        T item;
        public T Foo(string input) { Console.WriteLine(input); return item; }
    }
}

点网小提琴

至少

在您的 DotNetFiddle 示例中,您可以通过将泛型约束更改为 where T: Item, new() 来使第一个分配给funcA成为可能。

在第二个赋值中,委托将类型 T 用作返回类型和参数类型。我相信这会导致协方差和逆变的奇怪效应(MSDN 关于协变/逆变):让我们假设一个泛型实例使用一个类型class SubItem : Item {...}对于类TypedFactory<T>的类型参数T

可以使用SubItem作为返回类型,因为返回类型仍将是(子)类型 Item 和委托变量(例如 funcA ) 仍然"满足"委托类型声明所描述的协定。

但是,如果我们使用 SubItem 作为参数类型会发生什么?委托变量(例如 funcB )不能再在委托类型的声明所承诺的每个上下文中调用,例如 Item blubb; factory.funcB("I am alive too", blubb)是不可能的 - 类型不匹配,因为blubb不是类型 SubItem .由于可能会发生这种情况,编译器必须在此处抱怨。

也许您可以选择使代表通用?

using System;
public interface IItem
{
    string id {get;set;}
}

public class Item : IItem
{
    public string id{get;set;}
}
public class BaseFactory<T>
    where T: IItem, new()
{
    public DelegateHolder.MakeWithID<T> funcA;
    public DelegateHolder.MakeWithIDAndOther<T> funcB;
}
public class TypedFactory<T> : BaseFactory<T>
    where T : IItem, new()
{
        public TypedFactory()
        {
            funcA = makeNew;
            funcB = makeNewFromOther;
        }
        public T makeNew(string itemId)
        {
            T _item = new T();
            _item.id = itemId;
            return _item;
        }
        public T makeNewFromOther(string itemId, T other)
        {
            T _item = new T();
            _item.id = itemId;
            return _item;
        }
}
public class DelegateHolder
{
    public delegate T MakeWithID<T>(string id) where T: IItem, new();
    public delegate T MakeWithIDAndOther<T>(string id, T other) where T: IItem, new();
}
public class Program
{
    public static void Main()
    {
        var x = new TypedFactory<Item>();
        BaseFactory<Item> factory = x;
        Item someItem = factory.funcA("I am alive");
        Console.WriteLine(someItem.id);
        Console.WriteLine(factory.funcB("I am alive too", someItem).id);
    }
}