Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/320.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 泛型和显式/隐式运算符_C#_Generics_Casting_Operators - Fatal编程技术网

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);