.NET接口允许来自非派生类型的隐式强制转换

时间:2016-08-21 00:11:35

标签: c# .net interface

当我注意到this奇怪的部分时,我正在阅读Roslyn源代码:

    // Implicit casts are not emitted. As a result verifier may operate on a different 
    // types from the types of operands when performing stack merges in coalesce/ternary.
    // Such differences are in general irrelevant since merging rules work the same way
    // for base and derived types.
    //
    // Situation becomes more complicated with delegates, arrays and interfaces since they 
    // allow implicit casts from types that do not derive from them. In such cases
    // we may need to introduce static casts in the code to prod the verifier to the 
    // right direction

我很想知道这会发生什么。我特别关心接口何时允许来自非派生类型的隐式转换。但是,对数组/代理的解释也很有趣。

1 个答案:

答案 0 :(得分:2)

它似乎是泛型中协方差的经典示例:您可以使用具有更通用类的接口而不是派生类。

所以他们

  

"允许来自不是从它们派生的类型的隐式强制转换"

因为在这里你有一个从具有基类型的接口到具有派生类型的接口的隐式转换,因此来自不从它们派生的类型(具有基类型的接口)(具有派生类型的接口)。 / p>

在我的例子中,你可以看到一个协变接口,它计算一个更加派生的形状的区域,因为它是较少派生的形状,所以你实际上有一个演员 - 例如 - 一个尺寸丢失了......

public class Basic 
{
    public double dim1;

}

public class Derived  : Basic
{
    public double dim2;
}


public interface IFactory<in T>
{
    double Area(T shape);
}

class BasicFactory : IFactory<Basic>
{
    public double Area(Basic shape)
    {
        return shape.dim1 * shape.dim1;
    }
}

class DerivedFactory : IFactory<Derived>
{
    public double Area(Derived shape)
    {
        return shape.dim1 * shape.dim2;
    }
}

class Program 
{
    double Area(IFactory<Derived> factory, Derived shape)
    {
        return factory.Area(shape);
    }

    static void Main(string[] args)
    {

        IFactory<Basic> notDerived = new BasicFactory(); // from not derived type
        Derived shape = new Derived() { dim1 = 10, dim2 = 20 };
        double area = new Program().Area(notDerived,shape); // cast! dimension loss
        Console.WriteLine(area); // 100 = 10*10
        IFactory<Derived> derived = new DerivedFactory(); //from derived type
        area = new Program().Area(derived, shape); // no cast, now
        Console.WriteLine(area); // 200 = 10*20
        Console.ReadKey();

    }

}