C# 带有泛型的隐式运算符不适用于接口
我基本上有以下类(在上找到的示例)C# 带有泛型的隐式运算符不适用于接口,c#,generics,implicit-conversion,C#,Generics,Implicit Conversion,我基本上有以下类(在上找到的示例) class-MyClass { 公共MyClass(T val) { 值=val; } 公共T值{get;set;} 公共静态隐式运算符MyClass(T someValue) { 返回新的MyClass(someValue); } 公共静态隐式运算符T(MyClass myClassInstance) { 返回myClassInstance.Value; } } 可以 MyClass<IFoo> foo1 = new Foo(); MyClas
class-MyClass
{
公共MyClass(T val)
{
值=val;
}
公共T值{get;set;}
公共静态隐式运算符MyClass(T someValue)
{
返回新的MyClass(someValue);
}
公共静态隐式运算符T(MyClass myClassInstance)
{
返回myClassInstance.Value;
}
}
可以
MyClass<IFoo> foo1 = new Foo();
MyClass<Foo> foo2 = new Foo();
//But not
MyClass<IFoo> foo3 = (IFoo)new Foo();
MyClass foo1=new Foo();
MyClass foo2=新的Foo();
//但不是
MyClass foo3=(IFoo)new Foo();
真正的问题发生在尝试执行以下操作时
void Bar(IFoo foo)
{
Bar2(foo);
//What should be the same as
Bar2<IFoo>(new MyClass<IFoo>(foo));
}
void Bar2<T>(MyClass<T> myClass)
{
//Do stuff
}
void条(IFoo-foo)
{
Bar2(foo);
//什么应该是相同的
Bar2(新MyClass(foo));
}
无效条2(MyClass MyClass)
{
//做事
}
我如何重构MyClass,以便在只知道接口的情况下使用对象?简短回答:
用户定义的隐式转换在接口上不起作用。不要试图让它工作。找到类型系统问题的另一个解决方案
长答覆:
这是C#设计团队深思熟虑的决定。原则是,当您进行涉及接口的转换时,您希望保留引用标识;您询问的是实现接口的对象的标识,而不是试图创建具有类似属性的类似对象
这里更大的原则是,用户定义的转换不应取代内置转换。但是,由于几乎任何类都可以被子类化,并且该子类可以实现几乎任何接口,因此很难静态地知道涉及接口的给定用户定义转换是否会取代内置转换
仅供参考,这是规范中一个特别棘手的部分,C#编译器在这里有一些bug。我怀疑您上面的一个案例利用了这些bug;事实上,现实世界中有这样的程序,这就是阻止我修复bug的原因
这些缺陷主要是由于该特性在泛型之前就设计好了,而在泛型引入了许多不可预见的复杂性之后,又没有充分地重新设计
有关详细信息,请参阅我在这里的大量评论,特别是那些被标记为故意违反规范的位,它们描述了接口转换的问题
如您所见,该文件的长度不到1000行,并且可能超过一半的注释。经过数周的仔细研究和与语言团队的多次讨论,这些语义才得以理清。一旦你在一个编译器中犯了错误,你通常必须在十年后彻底理解它,然后永远记住它,以免在升级时破坏客户。对于语言设计人员来说,有许多对象课程是关于C#如何将规范中这一模糊部分搞砸的
我如何重构MyClass,以便在只知道接口的情况下使用对象
不要尝试。将接口引用强制转换为实际的运行时类型,然后从那里使用它。或者显式地创建所需类型的实例,而不是通过隐式转换。不要试图玩隐式转换和接口的游戏;它将无法正常工作。使用“动态”关键字分配。你可以稍后区分它
var hook = Environment.Version < new Version(4, 0) ? (dynamic)
// .NET 2.0->3.5
new JITHook<MscorjitAddrProvider>() :
// .NET 4.0+
new JITHook<ClrjitAddrProvider>();
var hook=Environment.Version<新版本(4,0)?(动态)
//.NET 2.0->3.5
新的JITHook():
//.NET4.0+
新的JITHook();
有Foo1,Foo2,…,FooN。关键是MyClass不应该在意,因为Bar()不会知道。(未来可能会有FooX)。因此,转换为实际的运行时类型不是一个选项。如果我写‘void Bar(MyClass foo)’,我可以注入任何IFoo实现(Foo1,Foo2,…,FooN,FooX),因为在这一点上隐式转换将是有效的……那么这种情况(特别是对于unity)映射(它只包含一个T[,]),我希望能够编写公共静态隐式操作符Texture2D(Map Map)
,public static implicit operator Texture2D(Map-Map)
和public static implicit operator Texture2D(Map-Map)
方法但是我得到了CS0556错误,有没有办法解决这个问题?我不明白你到底想用这个来实现什么。MyClass总是使用IFoo对象(接口和实现),或者它可以使用其他任何东西吗?无论如何,如果您试图隐式转换接口,那么在C#(正如@EricLippert已经说过的)中不可能有多个IFoo实现(Foo1,Foo2,…FooN)。也可能有其他接口Bar(OtherInterface other){Bar2(other);}这个问题当然是实际问题的简化版本。对我来说,执行(MyClass)(otherClassObject为动态)
,其中otherClassObject
是一种接口类型,触发了MyClass
上定义的隐式强制转换。如果没有作为动态
,则不会触发强制转换。
var hook = Environment.Version < new Version(4, 0) ? (dynamic)
// .NET 2.0->3.5
new JITHook<MscorjitAddrProvider>() :
// .NET 4.0+
new JITHook<ClrjitAddrProvider>();