首页 > 解决方案 > 将抽象转换为派生实现的接口

问题描述

我听说在 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。但是由于我不能确定每个项目之间的类型Derived,或者继承自和实现OtherDerived的任何其他类型,我必须使用抽象基类型的数组。BaseISomething

当然我可以使用一个数组ISomething,但是我使用 Unity 并且接口在编辑模式下不会被序列化,我需要序列化该数组。

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

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

编辑:感谢更好的标题

标签: c#performanceinterfacecastingabstract

解决方案


你可以看到你的 C# 编译成的 IL:SharpLab IL 结果

你的循环:

    // 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()被称为 using callvirt,这基本上意味着调度。在这种情况下,这是因为您的对象的具体类型在编译时是未知的。

不过,我不会担心这个的性能,除非你分析并且你看到这个特定的代码是一个热点。


推荐阅读