Анонимные типы. Существуют ли какие-либо отличительные характеристики?

Есть ли что-нибудь для использования, чтобы определить, является ли тип на самом деле анонимным типом? Например, интерфейс и т.д.

Цель состоит в том, чтобы создать что-то вроде следующего...

//defined like...
public static T Get<T>(this IAnonymous obj, string prop) {
    return (T)obj.GetType().GetProperty(prop).GetValue(obj, null);
}
//...

//And then used like...
var something = new { name = "John", age = 25 };
int age = something.Get<int>("age");

Или это просто красота анонимного типа? Нельзя идентифицировать его сам, потому что он принимает новую форму?

Примечание. Я понимаю, что вы можете написать метод расширения для класса object, но, на мой взгляд, это кажется немного излишним.

Ответ 1

EDIT: приведенный ниже список относится к анонимным типам С#. VB.NET имеет разные правила - в частности, он может генерировать изменчивые анонимные типы (и делает по умолчанию). Джаред отметил в комментарии, что стиль именования тоже отличается. В основном это все довольно хрупкое...

Вы не можете идентифицировать его в общем ограничении, но:

  • Это будет класс (а не интерфейс, enum, struct и т.д.).
  • Он будет использовать CompilerGeneratedAttribute
  • Он будет переопределять Equals, GetHashCode и ToString
  • Он будет находиться в глобальном пространстве имен
  • Он не будет вложен в другой тип
  • Он будет внутренним
  • Он будет запечатан
  • Он будет выводиться непосредственно из object
  • Он будет общим с таким количеством параметров типа, как свойства. (У вас может быть нетривиальный анонимный тип без свойств. Это немного бессмысленно.)
  • Каждое свойство будет иметь параметр типа с именем, включающим имя свойства, и будет иметь этот параметр типа, например. свойство Name становится свойством типа < > _ Name
  • Каждое свойство будет общедоступным и доступным только для чтения
  • Для каждого свойства будет соответствующее частное поле readonly
  • Других свойств или полей не будет.
  • Будет конструктор, принимающий один параметр, соответствующий каждому параметру типа, в том же порядке, что и параметры типа
  • В каждом методе и свойстве будет применен DebuggerHiddenAttribute.
  • Название типа начнется с "< > " и будет содержать "Анонимный тип"

Однако очень мало этого гарантируется спецификацией - так что все они могут измениться в следующей версии компилятора, или если вы используете Mono и т.д.

Ответ 2

Насколько я помню, существует [CompilerGenerated] marker... 2 сек.

Плюс имя будет причудливым, и это будет общий тип; -p

Собственно, для "get" и т.д. я, вероятно, просто использовал бы статический (нерасширяющий) метод.

Если вам просто нужен способ получить значение из экземпляра anon-type (в более поздний момент времени), возможно, наилучшим вариантом является лямбда - обратите внимание, что вам нужно несколько трюков, чтобы снять это:

    static void Main()
    {
        var foo = new { name = "John", age = 25 };
        var func = Get(foo, x => x.age);
        var bar = new { name = "Marc", age = 30 };
        int age = func(bar);
    }
    // template here is just for type inference...
    static Func<TSource, TValue> Get<TSource, TValue>(
        TSource template, Func<TSource, TValue> lambda)
    {
        return lambda;
    }

(отредактируйте комментарий). Определенно этот атрибут:

        var foo = new { A = "B" };
        Type type = foo.GetType();

        CompilerGeneratedAttribute attrib = (CompilerGeneratedAttribute) Attribute.GetCustomAttribute(
            type, typeof(CompilerGeneratedAttribute)); // non-null, therefore is compiler-generated

Ответ 3

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