. net接口允许从非派生类型进行隐式强制转换

本文关键字:转换 类型 接口 派生 net | 更新日期: 2023-09-27 18:03:27

我在阅读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

我很好奇这需要什么才能发生。我特别关心的是,接口何时允许从非派生类型进行隐式强制转换。不过,对数组/委托的解释也会很有趣。

. net接口允许从非派生类型进行隐式强制转换

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

所以他们

"允许非派生类型的隐式强制转换"

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

在我的例子中,你可以看到一个协变接口,它计算一个更派生的形状的面积,就像它是一个派生较少的形状一样,所以你实际上有一个强制转换,例如,一个维度丢失了…

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