一方面,我有以下代表:
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;
我得到了错误的回复类型&#39;错误。我知道委托签名必须匹配方法签名,但是因为&#34;其中&#34;通用中的指令实际上明确指出T 是 IBar,为什么它不起作用?
所以两个问题合而为一: - 为什么编译器拒绝考虑方法签名是否匹配? - 更重要的是,我怎样才能做到这一点?我更喜欢一个委托友好的解决方案,而不是因为惯例而使用Func。
注意:我试着四处寻找答案,但我可能对这个问题有错误的措辞,所以请随意拍我的脸如果以前已经回答过。
编辑:正如@Jonathon Chase指出的那样,我的示例代码并没有完全解决问题。可以找到一个非工作示例here。编辑上面的代码以反映问题。
编辑2 :所有答案都非常适合我,非常感谢您的时间。如果可以的话,我会检查所有三个!
答案 0 :(得分:4)
&#34;错误的返回类型&#34;错误是因为variance不是support value types。因此,class
实施IBar
可以转换,而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
分配{ {1}}。如果向FooDelegate
添加class
约束,则代码将编译。
MyClass<T>
答案 1 :(得分:3)
这里的例子肯定会有其他事情发生。我目前能够编译并运行以下示例并获得预期结果:
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; }
}
}
答案 2 :(得分:2)
至少在您的DotNetFiddle示例中,您可以通过将通用约束更改为funcA
来对where T: Item, new()
进行第一次分配。
在第二个赋值中,委托使用类型T作为返回类型和参数类型。我相信这会导致协方差和逆变的有时奇怪的影响(getaddrinfo()
):
我们假设一个通用实例使用类型class SubItem : Item {...}
对于您的班级T
的类型参数TypedFactory<T>
。
可以使用SubItem
作为返回类型,因为返回类型仍然是(子)类型Item
,而委托变量(例如funcA
)仍然是&# 34;满足&#34;委托类型声明所描述的合同。
但如果我们将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);
}
}