将摘要转换为由Derived实现的接口

时间:2019-01-11 23:31:04

标签: c# performance interface casting abstract

我听说在c#中,向上转换是在编译时完成的,因此使用起来确实很便宜。 但是在这种情况下,我希望转换的类型是抽象的,并且不能直接实现我想要转换的接口。

以下是示例:

public interface ISomething
{
   void Method();
}

public abstract class Base { }

public class Derived : Base, ISomething 
{
    public void Method() { }
}

public class OtherDerived : Base, ISomething
{
    public void Method() { }
}

public class SomeClass
{
    private Base[] _baseArray;

    public void SomeMethod()
    {
        foreach (var item in _baseArray)
            ((ISomething) item).Method();
    }
}

很明显,我处于_baseArray的每个项目实际上都是从Base继承并实现ISomething的类型的情况。 但是,由于我无法确定DerivedOtherDerived或从Base继承并实现ISomething的任何其他类型之间的每个项目是什么类型,我必须使用抽象基本类型的数组。

我当然可以使用ISomething的数组,但是我使用Unity,并且在编辑模式下不会对接口进行序列化,因此需要对该数组进行序列化。

所以,既然上下文在这里,我的问题是: 是否在编译时将item强制转换为ISomething?如果不是这样,它是否足够便宜以至于可以经常进行(准确地说是每一帧)?

感谢您的关注,对不起,如果我不太清楚,我不是英语,所以这并不容易。

编辑:感谢您提供的更好的标题

1 个答案:

答案 0 :(得分:3)

您可以看到C#编译为的IL:SharpLab IL Results

您的循环:

    // loop start (head: IL_0021)
        IL_000d: ldloc.0
        IL_000e: ldloc.1
        IL_000f: ldelem.ref
        IL_0010: stloc.2
        IL_0011: ldloc.2
        IL_0012: castclass ISomething
        IL_0017: callvirt instance void ISomething::Method()
        IL_001c: nop
        // sequence point: hidden
        IL_001d: ldloc.1
        IL_001e: ldc.i4.1
        IL_001f: add
        IL_0020: stloc.1

        IL_0021: ldloc.1
        IL_0022: ldloc.0
        IL_0023: ldlen
        IL_0024: conv.i4
        IL_0025: blt.s IL_000d
    // end loop

Method()使用callvirt进行调用,这基本上意味着调度。在这种情况下,这是因为在编译时未知对象的特定类型。

不过,除非您进行概要分析并且看到此特定代码是一个热点,否则我不会担心它的性能。