Ответ 1
Посмотрите на следующий код:
using System;
using System.Collections.Generic;
public class Program
{
public static void Main(string[] args)
{
Console.WriteLine("first");
// works perfectly!!!
dynamic foo = new { x=(Action)(() => Console.WriteLine("ok")) };
foo.x();
// fails
dynamic foo2 = new { x=(object)(Action)(() => Console.WriteLine("ok2")) };
foo2.x();
}
}
dynamic
использует метод отражения для доступа к объектам и полям, и поскольку он не может знать точные типы, он должен полагаться на информацию о типе, присутствующую в объектах, на которых он работает.
Когда поле x
в анонимном типе правильно вводится, поскольку вызов делегата foo.x()
работает, потому что динамическое может видеть, что значение поля является делегатом.
Когда вы используете
static dynamic ConstructSomeObj(dynamic param)
{ return new { x = param }; }
чтобы создать анонимный класс, созданный вами классом с полем x
типа object
(динамический object
за кулисами). Когда вы вызываете obj.x
dynamic, этот тип поля является object
, и он не хочет проверять, какой именно тип указывает это поле. И поскольку у объекта нет метода Invoke()
, такого как делегаты, он генерирует исключение. Если вы измените тип параметра метода на Action
, он будет работать.
Я предполагаю, что это решение для проверки типа поля вместо типа значения, которое содержит поле, было принято для обеспечения лучшей производительности. Другими словами, когда вы проверяете тип поля CallSite
, класс, сгенерированный dynamic
, может быть кэширован и повторно использован позже.
EDIT: проверено это на моно, может ли кто-нибудь проверить VS