Анонимные типы - есть ли какие-то особенные характеристики? - PullRequest
26 голосов
/ 24 ноября 2008

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

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

//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 , но, на мой взгляд, это немного излишне.

Ответы [ 3 ]

55 голосов
/ 24 ноября 2008

РЕДАКТИРОВАТЬ: Список ниже относится к анонимным типам C #. VB.NET имеет разные правила - в частности, он может генерировать изменяемые анонимные типы (и делает это по умолчанию). Джаред указал в комментарии, что стиль именования тоже другой. По сути, все это довольно хрупко ...

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

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

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

4 голосов
/ 24 ноября 2008

Насколько я помню, есть маркер [CompilerGenerated] ... 2 секунды

Кроме того, имя будет причудливым и универсальным; -p

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

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

    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
0 голосов
/ 24 ноября 2008

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

...