3

考虑以下场景。

我有一个返回的方法ISomething,但它可能是Somethingor Wrapped<Something>。因此,我将结果转换Something为使用它,但它失败了,任何关于为什么或如何解决它的帮助将不胜感激。

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

看来,如果在尝试强制转换时将类型暴露为接口,那么找不到运算符?

“简单”的解决方案是编写一个“解包”函数,它可以选择解开Wrapped<Something>to Something,但如果可能的话,我更喜欢使用运算符。

编辑

我认为问题的症结在于:在外面_GetSomething()我不知道是否SomethingWrapped<Something>被退回。

4

3 回答 3

4

显式转换在编译时绑定(额外提示是转换运算符是静态的)。

尝试

var f = (Something)(Wrapped<Something>)_GetSomething(true);

这成功了

在您的情况下,编译器只知道您的类型是ISomething并且不知道如何将 a 转换ISomething为 a Something,除非它Something已经是 a 。

通过更改public class Wrapped<T> : ISomethingpublic class Wrapped<T> : Something您的示例执行良好,但您的演员表没有被调用,因为Wrapped<T>已经是T.

注意:
不是explicit operator强制转换,而是类型转换,它是一个调用的方法,并且该方法根据编译时类型(在您的情况下ISomething)解析。类型转换与类型转换具有相同的语法,这是一个令人困惑的根源。转换只是将现有对象分配给兼容类型的不同变量,而类型转换实际上返回一个新对象。

于 2012-04-13T07:19:18.857 回答
2

您转换运算符如下所示:

public static explicit operator T(Wrapped<T> wrapped)
{
        return wrapped._something;
}

你在投

var d = (Something)_GetSomething(true); //FAILS!

你不能投到Something,原因Something具体的执行T:ISomething。要完成这项工作,您需要编写:

var d = (ISomething)_GetSomething(true); //SUCCESS!

或者

如果你真的想使用具体类型,你可以定义泛型,如:

public class Wrapped<T> : Something //Something and NOT ISomething 
    where T : ISomething
{
    .....
    .....
}
于 2012-04-13T07:18:05.457 回答
0
var d = (Something)(Wrapped<Something>)_GetSomething(true); 
var e = (Something)new Wrapped<Something>(a);
于 2012-04-13T07:24:01.207 回答