Подтвердить что ты не робот

Список <Object> vs List <dynamic>

Мне нужно создать гетерогенный List объектов (пользовательских классов). Моя первая мысль заключалась в создании List<ISomeMarkerInterface>, но я быстро понял, что это не то, что я хочу. Моя следующая мысль была List<dynamic>, и это, казалось, не плохая идея. Тем не менее, я занимался некоторыми исследованиями и наткнулся на эту статью о боксе и распаковке, и в этом примере они делают в основном то, что я хочу использовать List<Object>.

Помимо того, что dynamic будет оцениваться во время выполнения и Object во время компиляции, в чем разница между List<dynamic> и List<Object>? Разве это не одно и то же?

4b9b3361

Ответ 1

В С#: объект, var и динамика есть 3 "общих" типа (хотя не все являются реальными типами).

Объект

Фактический тип, как и любой другой тип, с одним специальным правилом: если тип не наследует, он наследует объект. Из этого следует, что все типы наследуются от объекта, прямо или косвенно.

Акцент: объект - это тип. Объект может быть объекта типа, а тип имеет свои методы, такие как ToString(). Поскольку все наследуется от объекта, все может быть выросло в объект. Когда вы назначаете объект объектной ссылке, вы делаете восходящий поток точно так же, как если вы назначаете объект типа Elephant на ссылку Animal, где Elephant наследуется от Animal.

SomeType x = new SomeType();
object obj = x;
obj.DoSomething();
  • obj рассматривается как объект типа во время компиляции и будет иметь объект типа во время выполнения (что является логическим, поскольку он является фактическим типом - obj объявляется как объект, поэтому может быть только такого типа)
  • obj.DoSomething() вызовет ошибку времени компиляции, поскольку объект не имеет этого метода, независимо от того, имеет ли его тип SomeType.

Var

Это не фактический тип, это просто сокращение для "компилятора, укажите тип для меня, основанный на правой стороне задания".

SomeType x = new SomeType();
var obj = x;
obj.DoSomething();
  • obj рассматривается как тип SomeType во время компиляции и будет иметь тип SomeType во время выполнения, точно так же, как если бы вы написали "SomeType" вместо "var".
  • Если SomeType имеет метод DoSomething(), этот код будет работать
  • Если SomeType не имеет метода, код вызовет ошибку времени компиляции

Динамический

Это тип, который сообщает компилятору отключить проверку типа компиляции по переменной. Объект рассматривается как имеющий тип dynamic во время компиляции и времени выполнения.

SomeType x = new SomeType();
dynamic obj = x;
obj.DoSomething();
  • obj имеет тип dynamic при компиляции и времени выполнения
  • Если SomeType имеет метод DoSomething(), этот код будет работать
  • если SomeType не имеет метода, код будет компилироваться, но вызывать исключение во время выполнения
  • Обратите внимание, что динамика может очень легко вызвать исключения, если используется небрежно:

    public void f(dynamic x)
    { 
        x.DoSomething();
    }
    

Это вызовет исключение, если x имеет тип, который не имеет метода DoSomething, но все равно можно вызвать его и передать любой объект в качестве параметра без ошибки времени компиляции, вызывая ошибку, которая отображается только во время выполнения и, возможно, только в определенных обстоятельствах - потенциальная ошибка. Поэтому, если вы используете динамику в любом виде открытого интерфейса класса, вы всегда должны вручную вводить проверку во время выполнения с помощью отражения, тщательно разбираться с исключениями или не делать этого в первую очередь.

Примечание: объект, на который ссылается, никогда не меняет свой тип, конечно. Хотя obj может быть объектом, x, к которому он относится, по-прежнему является SomeType.

Ответ 2

Разница в том, что если вы используете объект и пытаетесь получить доступ к некоторому члену вашего объекта, это будет ошибка времени компиляции (поскольку объект не имеет этого члена). Чтобы работать, вам нужно знать, что это за тип, и бросить его.

С динамикой вы можете получить доступ к любому члену - не компилировать ошибку времени. Если член не существует во время выполнения, это будет ошибка времени выполнения. Это путь, если вы знаете, что у ваших однородных объектов есть один и тот же элемент, например.

Однако, если это так, есть еще одно более четкое решение: вы можете определить интерфейс с этим членом, а затем сделать все ваши стандартные объекты реализованы, а ваш список может быть List<IYourInterface>.

Имейте в виду, что динамическая производительность может быть немного хуже из-за динамического разрешения типа.