泛型和显式/隐式运算符

时间:2012-04-13 07:01:40

标签: c# generics casting operators

请考虑以下情况。

我有一个返回ISomething的方法,但可能是SomethingWrapped<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>展开到Something,但我更愿意使用运算符。

修改

我认为问题的症结在于:_GetSomething()之外我不知道是否会返回SomethingWrapped<Something>

3 个答案:

答案 0 :(得分:4)

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

尝试

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

这成功了

在您的情况下,编译器只知道您的类型为ISomething,并且不知道如何将ISomething转换为Something,除非该事件发生为Something已经

通过将public class Wrapped<T> : ISomething更改为public class Wrapped<T> : Something您的示例执行正常,但由于Wrapped<T>已经是T,因此不会调用您的演员。

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

答案 1 :(得分:2)

你施放的操作符如下所示:

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

你就像

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

您无法转换为Something,因为SomethingT:ISomething具体实现。为了完成这项工作,你需要写:

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

如果确实想要使用具体的类型,您可以定义类似的通用:

public class Wrapped<T> : Something //Something and NOT ISomething 
    where T : ISomething
{
    .....
    .....
}

答案 2 :(得分:0)

var d = (Something)(Wrapped<Something>)_GetSomething(true); 
var e = (Something)new Wrapped<Something>(a);