C# “代表”;“返回类型错误”;
一方面,我有以下代表:C# “代表”;“返回类型错误”;,c#,delegates,C#,Delegates,一方面,我有以下代表: 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 FooDelegateWith
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){ ... }
}
我得到一个“错误的返回类型”错误。我知道委托签名必须与方法签名匹配,但既然泛型中的“where”指令实际上明确指定T是IBar,为什么它不起作用
因此,两个问题合一:
-为什么编译器拒绝考虑方法签名匹配?
-更重要的是,我如何才能使这项工作?出于惯例的原因,我更喜欢代表友好的解决方案,而不是使用Func
注意:我试着四处寻找答案,但我可能对这个问题有错误的措辞,所以如果以前有人回答过,请随意打我一耳光
编辑:正如@Jonathon Chase指出的,我的示例代码并没有完全解决这个问题。可以找到一个不起作用的例子。编辑上述代码以反映问题
编辑2:所有答案对我来说都非常有用,非常感谢您抽出时间。如果可以的话,我会把这三个都检查一遍 您的示例中肯定还有其他原因。我目前能够编译并运行以下示例,并收到预期结果:
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; }
}
}
公共类程序
{
公共静态void Main()
{
var x=新的MyClass();
Foo委托测试=x.Foo;
测试(“做它”);
}
公共委托IBar FOODERegate(字符串str);
公共接口IBar{}
公共类栏:IBar{}
公共类MyClass,其中T:IBar,new()
{
T项;
公共T Foo(字符串输入){Console.WriteLine(输入);返回项;}
}
}
至少在您的DotNetFiddle示例中,您可以通过将通用约束更改为
,其中T:Item,new()
来实现对funcA
的第一次赋值
在第二个赋值中,委托使用类型T作为返回类型和参数类型。我相信这会导致协方差和反方差有时会产生奇怪的效果():
让我们假设泛型实例使用类型类子项:Item{…}
对于类TypedFactory
的类型参数T
可以使用子项
作为返回类型,因为返回类型仍然是(子)类型项
,并且委托变量(例如funcA
)仍然“满足”委托类型声明中描述的合同
但是如果我们使用子项
作为参数类型,会发生什么呢?委托变量(例如funcB
)不能再在委托类型声明承诺的每个上下文中调用,例如Item blubb;factory.funcB(“我也活着”,blubb)
不可能-类型不匹配,因为blubb
不是子项的类型。由于这种情况可能发生,编译器不得不在这里抱怨
也许您可以选择将代理设置为通用的
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);
}
}
使用系统;
公共接口项
{
字符串id{get;set;}
}
公共类项目:IItem
{
公共字符串id{get;set;}
}
公共类基工厂
其中T:IItem,new()
{
public DelegateHolder.MakeWithID funcA;
public DelegateHolder.makewithid和其他functb;
}
公共类TypedFactory:BaseFactory
其中T:IItem,new()
{
公共类型工厂()
{
funcA=makeNew;
funcB=makenewfromther;
}
public T makeNew(字符串itemId)
{
T_项=新的T();
_item.id=itemId;
退货项目;
}
公共T makeNewFromOther(字符串itemId,T other)
{
T_项=新的T();
_item.id=itemId;
退货项目;
}
}
公共类委托人
{
公共委托T MakeWithID(字符串id),其中T:IItem,new();
公共委托T MakeWithIDAndOther(字符串id,T other),其中T:IItem,new();
}
公共课程
{
公共静态void Main()
{
var x=新类型工厂();
基本工厂=x;
Item someItem=factory.funcA(“我还活着”);
Console.WriteLine(someItem.id);
Console.WriteLine(factory.funcB(“我也活着”,someItem).id);
}
}
错误的返回类型是因为没有。因此可以转换类
实现IBar
,而结构
实现不会:
class RefTypeBar : IBar {}
struct ValueTypeBar : IBar {}
FooDelegate f1 = new MyClass<RefTypeBar>().Foo; // This works
FooDelegate f2 = new MyClass<ValueTypeBar().Foo; // Fails - wrong return type
你是对的,我认为我发布的简短版本会出现问题,但事实并非如此。显然,对于委托,我还没有意识到一些微妙之处,下面是我在DotNetFiddle上遇到的问题的一个例子:哦,在这种情况下,问题是试图将非泛型委托应用于泛型函数。如果您使用相同的约束使委托成为泛型的,则应该可以,或者尝试将其应用于已声明实例上的方法,就像我在上面的代码示例中所做的那样。但我不能使其成为泛型的,基类只能处理接口,而不知道其泛型子类:(我要么需要牺牲泛型实现的某些部分来使用接口而不是T,要么创建一个与委托签名匹配的伪函数,这将破坏其最初的目的。愚蠢的我认为,使用接口作为泛型约束也隐含着“类”——我不知道你可以使用接口带值类型的es。解决了第一个问题,添加类是一种方法。确实,我可以使用泛型委托,但在基类上,我只需要处理接口,所以我不能在这里真正使用这个技巧…:(非常有用--非常感谢!
class RefTypeBar : IBar {}
struct ValueTypeBar : IBar {}
FooDelegate f1 = new MyClass<RefTypeBar>().Foo; // This works
FooDelegate f2 = new MyClass<ValueTypeBar().Foo; // Fails - wrong return type
public class MyClass<T> : MyBaseClass where T : class, IBar, new()