Может ли "динамический" тип безопасно меняться в общей коллекции <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);
}