Анонимные типы - есть ли какие-нибудь отличительные черты?

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

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

//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");

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

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


person hugoware    schedule 24.11.2008    source источник


Ответы (3)


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

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

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

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

person Jon Skeet    schedule 24.11.2008
comment
Префикс имени ‹› используется только для C #. В VB префиксом имени будет VB $ AnonymousType. - person JaredPar; 24.11.2008
comment
О, это стоит знать. Осмелюсь сказать, что многие другие вещи применимы только к C #, особенно потому, что VB могут быть изменяемыми. Отредактируем, чтобы отразить это. - person Jon Skeet; 24.11.2008
comment
Я просмотрел остальные записи и обнаружил только две другие ошибки VB. Поля не имеют префикса имени ‹› _. Также версия VB имеет дополнительное частное свойство под названием AtDebuggerDisplay, которое используется для повышения производительности при отладке. - person JaredPar; 25.11.2008
comment
Правильно. Я могу пересмотреть ответ в какой-то момент, чтобы иметь общие разделы / C # / VB. Хотя он все равно будет хрупким :( - person Jon Skeet; 25.11.2008
comment
Еще лучшим решением было бы сделать анонимные типы именованными. Или исправить все остроумие, набирая утку :) - person JaredPar; 25.11.2008
comment
Я не знаю, зачем кому-то это делать, но если переданный анонимный тип является новым {}, он не будет общим и будет иметь конструктор по умолчанию. - person Matthew Whited; 07.06.2009

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

К тому же имя будет странным, и это будет общий тип ;-p

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

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

    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
person Marc Gravell    schedule 24.11.2008
comment
Нет, нет атрибута, созданного компилятором - person JaredPar; 24.11.2008
comment
@JaredPar: Конечно, в моем маленьком тесте. - person Jon Skeet; 24.11.2008
comment
[CompilerGenerated] выделяет гораздо большую вселенную, которую вводят анонимные типы. - person JaredPar; 24.11.2008
comment
@JaredPar - действительно ... это может быть замыкание, итератор и т. Д. Но эти характеристики ([CompilerGenerated], родовое, ужасное имя) - единственное, что у вас есть. Фактически, вы можете проверить, все ли поля доступны только для чтения - итераторов и замыканий не будет. Но не как общее ограничение. - person Marc Gravell; 24.11.2008
comment
Однако было бы более надежно проверить имя по сравнению с существованием CompilerGenerated. Есть много сторонних инструментов, которые используют атрибут CompilerGenerated. - person JaredPar; 24.11.2008
comment
Сочетания CompilerGenerated и not nested на самом деле может быть достаточно ... Я думаю, что clsoures и блоки итератора всегда оказываются вложенными. Хотя не очень перспективно. - person Jon Skeet; 24.11.2008
comment
@Jon, тоже не очень актуальное доказательство. Многие другие инструменты добавляют атрибут CompilerGenerated. Этот раствор будет работать только для строго ванильных растворов. Как только вы добавляете стороннюю DLL в свое приложение, это увеличивает вероятность взлома. - person JaredPar; 24.11.2008
comment
@ Джаред: Да, это действительно зависит от того, что вы делаете со знаниями. Если он находится в вашей собственной сборке, и вы знаете, что единственный задействованный инструмент - это компилятор C #, это одно ... но помимо этого, он невероятно хрупкий. - person Jon Skeet; 24.11.2008

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

person JaredPar    schedule 24.11.2008
comment
Что ж, вы не можете сделать более конкретную перегрузку для анонимного типа - однако методы расширения (в общем) в некотором смысле наиболее полезны с анонимными типами. - person Marc Gravell; 24.11.2008
comment
В каком смысле? Невозможно получить статический доступ к члену анонимного типа с помощью универсального метода расширения. Вы можете использовать великолепный взлом в неуниверсальном методе расширения, но он включает в себя создание неиспользуемого типа, приведение и получение значения - person JaredPar; 24.11.2008
comment
На самом деле вы можете - через лямбду и т. Д. Но общий метод расширения (например) IEnumerable ‹T› и т. Д. Является основным механизмом передачи строго типизированного анонимного типа (T) из метода и работы с ним в полезном способом (через Func ‹T›, Action ‹T› и т. д.). - person Marc Gravell; 24.11.2008
comment
(Хорошо, это не обязательно должен быть метод расширения, но это помогает для LINQ). Но, например ... list.Sum (x = ›x.Foo), где list - это анонимный тип, определяющий Foo. - person Marc Gravell; 24.11.2008
comment
Да, но анонимный тип используется в лямбда-выражении, а не в методе расширения. Нет способа получить статический доступ к членам анонимного типа в методе расширения, только лямбда. - person JaredPar; 24.11.2008
comment
Я пару раз использовал анонимные типы в полезных методах расширения, когда смотрел на них с отражением. В частности, они хорошо работают как быстрый способ создания XElements или XAttributes. - person Jon Skeet; 24.11.2008
comment
@JaredPar - вы единственный, кто говорит о том, где происходит статическая типизация. Дело в том, что с помощью лямбда-выражения и универсального метода (обычно с расширением, но не обязательно) вы можете выполнить свою работу, и это - наша цель. - person Marc Gravell; 24.11.2008
comment
@Mark, я не согласен. В вопросе явно указано, как сделать метод расширения анонимным. - person JaredPar; 24.11.2008
comment
@Jon, я обычно не рассматриваю статическую типизацию с отражением. Я понимаю, что это на самом деле статически типизировано, но это тоже не совсем :) - person JaredPar; 24.11.2008
comment
@Jared: Извините, я не пытался утверждать, что это была статическая типизация - просто все еще может быть очень полезно передать анонимный тип методу расширения, и действительно может быть полезно писать методы, которые по крайней мере < i> в первую очередь полезно с анонимными типами. - person Jon Skeet; 24.11.2008