Почему отличает динамический объект типа к объекту, выбрасывая исключение с нулевой ссылкой?

У меня есть следующая функция:

public static T TryGetArrayValue<T>(object[] array_, int index_)
{
    ... //some checking goes up here not relevant to question

    dynamic boxed = array_[index_];
    return (T)boxed;
}

Когда я вызываю его следующим образом,

object a = new object();
object v = TUtils.TryGetArrayValue<object>(new object[] { a }, 0);

(T)boxed выбрасывает исключение нулевой ссылки.

Любой другой тип, который я вставлял туда, кроме "object", работает отлично.
Любые идеи, что это такое, и почему это бросает исключение?

Изменить: Причина, по которой я использую динамику, заключается в том, чтобы избежать исключения при преобразовании типов, например:

double a = 123;
int v = TUtils.TryGetArrayValue<int>(new object[] { a }, 0);

Ответ 1

Я согласен с другими ответчиками, которые говорят, что это похоже на ошибку. В частности, это, по-видимому, ошибка в связующем слое С#, хотя я не исследовал его полностью.

Извиняюсь за ошибку. Я сообщу об этом команде тестирования С# 5, и мы увидим, что она уже была зарегистрирована и исправлена ​​на С# 5. (Она воспроизводится в последней бета-версии, поэтому маловероятно, что она уже была отмечена и исправлена. ) Если нет, исправление вряд ли сделает его окончательным. В этом случае мы рассмотрим его для возможного релиза обслуживания.

Спасибо, что привлекли это к нашему вниманию. Если вы чувствуете, что вводите проблему Connect, чтобы ее отслеживать, не стесняйтесь делать это и, пожалуйста, укажите ссылку на этот вопрос StackOverflow. Если вы этого не сделаете, никаких проблем; опытная команда будет знать об этом в любом случае.

Ответ 2

Это проблема с динамическими работами - связующее средство времени выполнения имеет проблему с преобразованиями из System.Object, но на практике это действительно не проблема.

Я подозреваю, что это потому, что dynamic, во время выполнения, сам всегда System.Object. Спецификация языка С# в 4.7 гласит: "Динамика типа неотличима от объекта во время выполнения". Таким образом, любой объект, используемый как динамический, просто сохраняется как объект.

Когда вы реальный экземпляр System.Object в динамический, то это встречающийся в обязательном разрешении выполнения, которое вызывает нулевое ссылочное исключение.

Однако любой другой тип, который не работает System.Object, работает - даже ссылочные типы и тому подобное, без ошибок. Таким образом, это должно обеспечить вам правильное поведение, поскольку на самом деле нет причин создавать экземпляр System.Object, который будет передан - вам всегда нужен какой-либо подкласс с информацией другого типа.

Как только вы используете какой-либо "настоящий" тип, это отлично работает. Для exmaple следующие работы, хотя они прошли и обрабатывались как Object:

public class Program
{
    public static T TryGetArrayValue<T>(object[] array_, int index_)
    {

        dynamic boxed = array_[index_];
        return (T)boxed;
    }

    private static void Main()
    {
        int p = 3;
        object a = p;
        var objects = new[] { a, 4.5 };

        // This works now, since the object is pointing to a class instance
        object v = TryGetArrayValue<object>(objects, 0);
        Console.WriteLine(v);

        // These both also work fine...
        double d = TryGetArrayValue<double>(objects, 1);
        Console.WriteLine(d);
        // Even the "automatic" int conversion works now
        int i = TryGetArrayValue<int>(objects, 1);
        Console.WriteLine(i);
        Console.ReadKey();
    }
}

Ответ 3

Это действительно странное поведение, и оно действительно выглядит как ошибка в реализации dynamic. Я обнаружил, что этот вариант не генерирует исключения и действительно возвращает объект:

public static T TryGetArrayValue<T>(object[] array, int index) where T : class
{
    dynamic boxed = array[index];
    return boxed as T;
}

Обратите внимание, что мне пришлось добавить обобщенное ограничение в сигнатуре метода, потому что оператор as работает только в том случае, если T является ссылочным типом.

Если вы ищете обходной путь, вы можете использовать это (и я знаю это уродливо):

public static T TryGetArrayValue<T>(object[] array, int index)
{
    dynamic boxed = array[index];

    if (typeof(T) == typeof(object))
        return (T)(boxed as object);

    return (T)boxed;
}

Ответ 4

Это как-то связано с ключевым словом dynamic. Если я изменил тип на T для коробки, он будет работать.

    static void Main(string[] args)
    {
        object a = new object();
        object v = TryGetArrayValue<object>(new object[] { a }, 0);

        Console.ReadLine();
    }

    public static T TryGetArrayValue<T>(object[] array_, int index_)
    {

            T boxed = (T)array_[index_];
            return boxed;

    }

Есть ли конкретная причина, по которой вы используете динамический? Вы действительно не нуждаетесь в этом в этом случае, поскольку знаете, что тип опережает время. Если вы посмотрите, в вашей версии тип boxed не является объектом, а является динамическим {object}, что может быть проблемой при попытке передать объект. Если вы посмотрите на эту версию, которую я опубликовал, вы получите тип объекта и никаких ошибок.