C# 泛型和显式/隐式运算符
考虑以下场景 我有一个方法返回C# 泛型和显式/隐式运算符,c#,generics,casting,operators,C#,Generics,Casting,Operators,考虑以下场景 我有一个方法返回ISomething,但它可以是Something或Wrapped。 因此,我将结果投射到某物以使用它,但它失败了,请提供任何关于为什么或如何解决它的帮助 class Program { static void Main(string[] args) { var a = new DerivedSomething(); var b = (DerivedSomething)new Wrapped<DerivedSom
ISomething
,但它可以是Something
或Wrapped
。
因此,我将结果投射到某物以使用它,但它失败了,请提供任何关于为什么或如何解决它的帮助
class Program
{
static void Main(string[] args)
{
var a = new DerivedSomething();
var b = (DerivedSomething)new Wrapped<DerivedSomething>(a); //success
var c = (DerivedSomething)_GetSomething(false); //success, obsiously!
var d = (DerivedSomething)_GetSomething(true); //Unable to cast object of type 'test_bed.Wrapped`1[test_bed.DerivedSomething]' to type 'test_bed.DerivedSomething'.
var e = (DerivedSomething)(ISomething)new Wrapped<DerivedSomething>(a); //Unable to cast object of type 'test_bed.Wrapped`1[test_bed.DerivedSomething]' to type 'test_bed.DerivedSomething'.
var works = ((DerivedSomething)_GetSomething(false)).DoSomethingElse();
var fails = ((DerivedSomething)_GetSomething(true)).DoSomethingElse(); //cast exception
}
private static ISomething _GetSomething(bool wrap)
{
var something = new DerivedSomething();
return wrap ? new Wrapped<DerivedSomething>(something) : (ISomething)something;
}
}
public interface ISomething
{
void DoSomething();
}
public abstract class Something : ISomething
{
public void DoSomething()
{
//some code
}
}
public class DerivedSomething : Something
{
public void DoSomething()
{
//some code
}
public void DoSomethingElse()
{
//some code
}
}
public class Wrapped<T> : ISomething
where T : ISomething
{
private readonly T _something;
public Wrapped(T something)
{
_something = something;
}
public void DoSomething()
{
_something.DoSomething();
}
public static explicit operator T(Wrapped<T> wrapped)
{
return wrapped._something;
}
}
类程序
{
静态void Main(字符串[]参数)
{
var a=新衍生的某物();
var b=(DerivedSomething)新包装(a);//成功
var c=(DerivedSomething)\u GetSomething(false);//成功,淫秽!
var d=(DerivedSomething)_GetSomething(true);//无法将类型为“test\u bed.Wrapped`1[test\u bed.DerivedSomething]”的对象强制转换为类型为“test\u bed.DerivedSomething”。
var e=(DerivedSomething)(ISomething)new Wrapped(a);//无法将类型为“test_bed.Wrapped`1[test_bed.DerivedSomething]”的对象强制转换为类型为“test_bed.DerivedSomething”。
var works=((派生的东西)u GetSomething(false)).DoSomethingElse();
var fails=((DerivedSomething)_GetSomething(true)).DoSomethingElse();//强制转换异常
}
私有静态对象_GetSomething(bool wrap)
{
var something=新衍生的something();
退货包装?新包装的(某物):(某物)某物;
}
}
公共接口
{
无效剂量();
}
公共抽象类某物:等轴物
{
公共无效剂量测定法()
{
//一些代码
}
}
公共阶级嘲笑的东西:东西
{
公共无效剂量测定法()
{
//一些代码
}
公共无效DoSomethingElse()
{
//一些代码
}
}
公共类:一件事
T:什么东西
{
私人只读文件;
公共包装(T什么的)
{
_某物=某物;
}
公共无效剂量测定法()
{
_做某事;
}
公共静态显式运算符T(已包装)
{
包装好的东西;
}
}
如果在尝试强制转换时将类型作为接口公开,那么是否找不到运算符
“简单”的解决方案是编写一个“unwrap”函数,该函数可以选择性地将包装的
展开到某物
,但如果可能的话,我更喜欢使用运算符
编辑
我认为问题的症结在于:在\u GetSomething()
之外,我不知道某个东西是要返回的还是要返回的包装的。您所使用的操作符如下所示:
public static explicit operator T(Wrapped<T> wrapped)
{
return wrapped._something;
}
您不能强制转换为Something
,因为Something
是T:ISomething
的具体实现。要实现这一目标,您需要编写:
var d = (ISomething)_GetSomething(true); //SUCCESS!
或
如果确实要使用具体类型,可以定义泛型,如:
public class Wrapped<T> : Something //Something and NOT ISomething
where T : ISomething
{
.....
.....
}
public类包装:Something//Something而不是Something
T:什么东西
{
.....
.....
}
显式转换在编译时绑定(额外的提示是convert运算符是静态的)
试一试
var f=(Something)(包装)\u GetSomething(true);
这成功了
在您的例子中,编译器只知道您的类型是ISomething
,不知道如何将ISomething
转换为Something
,除非它已经是Something
通过将public-class-Wrapped:ISomething
更改为public-class-Wrapped:Something
您的示例执行良好,但不会调用您的强制转换,因为Wrapped
已经是T
注意:
显式运算符
不是强制转换,而是类型转换,它是一个调用的方法,该方法基于编译时类型解析(在您的例子中是ISomething
)。类型转换与类型转换具有相同的语法,这是一个混乱的根源。强制转换只是将现有对象分配给兼容类型的不同变量,而类型转换实际上返回一个新对象。var d=(Something)(Wrapped)\u GetSomething(true);
var d = (Something)(Wrapped<Something>)_GetSomething(true);
var e = (Something)new Wrapped<Something>(a);
var e=(某物)新包装(a);
我认为Wrapped
不能转换为某个东西。我编译了您的示例,并验证了这一点。第一次强制转换(变量b
)应该失败……我猜您是在问为什么显式运算符t(Wrapped)
不允许对传递的具体类型而不仅仅是约束类型进行强制转换。@EthanBrown-显式强制转换是为执行强制转换而设计的,它在案例b中正常工作,问题是为什么它对案例D或E不起作用因此我将结果转换为某个东西来使用它:首先,为什么您需要向下转换为某个东西?它和Wrapped
都实现了ISomething
,这一事实清楚地表明,至少在某种程度上,它们应该是不可区分的。@Anton,希望问题中修改的代码能更好地突出我的问题?Albin,你的例子会起作用,除了false被传递给_GetSomething()的场景之外. 在这种情况下,某些内容
无法转换为包装的
。我的场景要求包装的
不继承,它只使用T
。编译器是否仅通过其公开的类型(ISomething
-作为\u GetSomething()
)而不是方法发出的实际类型来理解类型?@SimonLaing,您不能,因为类型必须在编译时已知(通过使用类型变量或强制转换)。我用一些关于强制转换和转换之间区别的注释更新了我的答案。@SimonLaing,当您创建界面ISomething
时,最好一直使用该界面,而不是尝试转换为具体类型。我认为类型转换是我在这里需要的,因为我介绍了一个
var f = (Something)(Wrapped<Something>)_GetSomething(true);
var d = (Something)(Wrapped<Something>)_GetSomething(true);
var e = (Something)new Wrapped<Something>(a);