Приведение абстрактных данных к интерфейсу, реализованному Derived - PullRequest
0 голосов
/ 12 января 2019

Я слышал, что в 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 или любыми другими типами, которые наследуются от Base и реализует ISomething, я должен использовать массив абстрактного базового типа.

Конечно, я мог бы использовать массив ISomething, но я использую Unity, и интерфейсы не будут сериализованы в режиме редактирования, и мне нужно сериализовать этот массив.

Итак, теперь, когда контекст здесь, мой вопрос следующий: Обработано ли приведение item к ISomething во время компиляции? И если это не так, достаточно ли это дешево, чтобы делать это очень часто (точнее, на каждом кадре)?

Спасибо за ваше внимание, и извините, если я не супер ясен, я не англичанин, так что это не очень легко.

Редактировать: Спасибо за лучший заголовок

1 Ответ

0 голосов
/ 12 января 2019

Вы можете увидеть IL, который ваш C # компилирует в: 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, что в основном означает отправку. В данном случае это потому, что конкретный тип вашего объекта неизвестен во время компиляции .

Я бы не стал беспокоиться о производительности этого, если только вы не профилируете и не увидите, что этот конкретный код является горячей точкой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...