Может ли "динамический" тип безопасно меняться в общей коллекции <dynamic>?

Основываясь на моем ответе на этот вопрос, я хочу проверить что-то на моем понимании предстоящего типа dynamic для С# 4.

В этом случае у нас есть коллекция, представляющая поля в записи, извлеченной из неизвестной таблицы базы данных. Старший код (pre-.Net 4) требует, чтобы такие элементы удержания коллекции имели тип Object. Достоинства такой коллекции в стороне, мне интересно, что произойдет, когда вы измените Object на dynamic.

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

С другой стороны, я задаюсь вопросом о слове "все" в предыдущем предложении. Будет ли время выполнения возможно кэшировать результаты при первом доступе динамического свойства, вызвав последующие вызовы с использованием разных типов?

Ответ 1

Вот соответствующий бит из блога Сэма, в котором кратко говорится о политике кэширования.

http://blogs.msdn.com/samng/archive/2008/10/29/dynamic-in-c.aspx

DLR проверяет кеш, чтобы узнать, данное действие уже связано против текущего набора аргументов. Итак, в нашем примере мы будем делать тип соответствие на основе 1, 2 и времени выполнения тип d. Если у нас есть кеш, то мы возвращаем кешированный результат. Если у нас нет кеша, тогда DLR проверяет, является ли приемник IDynamicObject. Эти ребята по существу объекты, которые знают, как позаботиться о своей собственной привязке, такой как объекты COM IDispatch, реальные динамические объекты, такие как Ruby или Python, или какой-либо .NET-объект, который реализует интерфейс IDynamicObject. Если это любой из них, тогда DLR отменяет к IDO и просит его связать действие.

Обратите внимание, что результат вызова IDO для привязки - это дерево выражений, которое представляет собой результат привязки. Если это не IDO, то DLR звонит в языковое связующее (в нашем case, связующее время выполнения С#) для связывания операция. Среда связывания С# свяжет действие и вернется дерево выражений, представляющее результат связывания. После шага 2 или 3 произошли, в результате Дерево выражений объединяется в механизма кеширования, чтобы любой последующие вызовы могут кеш, а не отскок.

Однако, что Сэм не упоминает, это именно то, что политика пропусков в кеше. Существуют две основные политики кэширования: (1) запуск кеша при изменении типов аргументов, (2) запуск кеша при изменении идентификаторов аргументов.

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

Ответ 2

Хорошо, а не ждать ответа, я активировал бета-версию Visual Studio 2010, и эта тестовая программа работает нормально:

class Foo
{
    public string foo = "Foo!";
}
class Bar
{
    public int bar = 42;
}

class Program
{
    static void Main(string[] args)
    {
        var test = new List<dynamic>();
        test.Add(new Foo());
        test.Add(new Bar());

        Console.WriteLine(test[0].foo.Substring(0,3));
        Console.WriteLine(test[1].bar.ToString("000"));

        Console.ReadKey(true);
    }
}

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

Ответ 3

Вы можете думать о динамике как о синтаксическом сахаре для написания всех вызовов метода с использованием Reflection и MethodInfo.Invoke() - под капотом это работает не так, но вы можете думать, что он работает именно так, со всеми "вызовами 1000 методов/сек через динамические = > убитые перфекционные" соображения, которые идут с ним.

Ответ 4

Что касается словаря/списка, он может просто увидеть object. dynamic в значительной степени находится в глазу наблюдателя, то есть вызывающего кода; под капотом это "объект плюс немного сахара". Поэтому здесь не должно возникать проблем.

Доказательство:

    static void Main()
    {
        Console.WriteLine(IsObject<int>()); // false
        Console.WriteLine(IsObject<object>()); // true
        Console.WriteLine(IsObject<dynamic>()); // true
        Console.WriteLine(IsObject<string>()); // false
    }
    static bool IsObject<T>()
    {
        return typeof(T) == typeof(object);
    }