views:

471

answers:

3

Is there anything to use, to determine if a type is actually a anonymous type? For example an interface, etc?

The goal is to create something like the following...

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

Or is that just the beauty of an anonymous type? Nothing to identify it self because it takes a new shape?

Note - I realize that you can write an extension method for the object class, but that seems like a little overkill, in my opinion.

+1  A: 

As I recall, there is a [CompilerGenerated] marker... 2 secs

Plus the name will be freaky, and it will be a generic type ;-p

Actually, for a "get" etc I would probably just use a static (non-extension) method.

If you just want a way to get the value from an instance of an anon-type (at a later point in time), a lambda is probably the best option - note you need a few tricks to pull this off:

    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;
    }

(edit re the comment) There definitely is this attribute:

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

        CompilerGeneratedAttribute attrib = (CompilerGeneratedAttribute) Attribute.GetCustomAttribute(
            type, typeof(CompilerGeneratedAttribute)); // non-null, therefore is compiler-generated
Marc Gravell
Nope, no compiler generated attribute
JaredPar
@JaredPar: There certainly is in my little test.
Jon Skeet
[CompilerGenerated] distiguishes a much larger universe that anonymous types.
JaredPar
@JaredPar - indeed... it could e a closure, and iterator, etc. But these characteristics ([CompilerGenerated], generic, horrible name) are the only things you have. Actually, you could check whether all the fields are readonly - iterators and closures won't be. But not as a generic constraint.
Marc Gravell
It would be more reliable though to check the name versus the existance of CompilerGenerated. There are many 3rd party tools that use the CompilerGenerated attribute.
JaredPar
Very interesting
Hugoware
The combination of "CompilerGenerated and not nested" may actually be enough... I think clsoures and iterator blocks always end up being nested. Not very future-proof though.
Jon Skeet
@Jon, also not very current proof. Many other tools add the CompilerGenerated attribute. This solution will only work for strictly vanilla solutions. Once you add a third party DLL to your application it adds the chance of breaking.
JaredPar
@Jared: Yes, it really depends on what you're doing with the knowledge. If it's within your own assembly and you know that the only tool involved is the C# compiler, that's one thing... but beyond that, it's incredibly fragile.
Jon Skeet
A: 

For the purposes of extension methods there is no way to distinguish an anonymous type. Extension methods work by specifying a method for a compile time nameable type. Anonymous types are un-namable and therefore not visible at compile time. This makes them incompatible with extension methods.

JaredPar
Well, you can't make a more-specific overload for an anonymous type - however, extension methods are (in general) in some ways at their *most* useful with anonymous types.
Marc Gravell
In what way? There is no way to statically access a member of an anonymous type via a generic extension method. You can use a glorious hack in a non-generic extension method but it involves creating a non-used type, casting and getting the value
JaredPar
Actually you can - via a lambda etc. But a generic extension method on (for example) IEnumerable<T> etc is the primary mechanism of passing a strongly typed anon-type (T) out of a method and working with it in a useful way (via Func<T>, Action<T>, etc).
Marc Gravell
(OK, it needn't be an extension method, but that helps for LINQ). But for example... list.Sum(x=>x.Foo) where list is an anon-type that defines Foo.
Marc Gravell
Yes but the use of the anonymous type is in the lambda, not the extension method. There is no way to access the anonymous type members statically within the extension method, only the lambda.
JaredPar
I've used anonymous types a couple of times in useful extension methods, when looking at them with reflection. In particular they work well as a quick way of generating XElements or XAttributes.
Jon Skeet
@JaredPar - you're the only one talking about where the static typing happens. The point is, that with a lambda and generic method (extension commonly, but not necessarily) you can get the job done, and *that* is our aim.
Marc Gravell
@Mark, I disagree. The question explicitly states "how can I make an extension method typed to an anonymous type".
JaredPar
@Jon, I usually don't consider reflection static typing. I understand it is actually statically typed but it's also not really :)
JaredPar
@Jared: Sorry, I wasn't trying to claim that it was static typing - just that it can still be very useful to pass an anonymous type to an extension method, and indeed it can be useful to write methods which are at least *primarily* useful with anonymous types.
Jon Skeet
+9  A: 

EDIT: The list below applies to C# anonymous types. VB.NET has different rules - in particular, it can generate mutable anonymous types (and does by default). Jared has pointed out in the comment that the naming style is different, too. Basically this is all pretty fragile...

You can't identify it in a generic constraint, but:

  • It will be a class (rather than interface, enum, struct etc)
  • It will have the CompilerGeneratedAttribute applied to it
  • It will override Equals, GetHashCode and ToString
  • It will be in the global namespace
  • It will not be nested in another type
  • It will be internal
  • It will be sealed
  • It will derive directly from object
  • It will be generic with as many type parameters as properties. (You can have a non-generic anonymous type, with no properties. It's a bit pointless though.)
  • Each property will have a type parameter with a name including the property name, and will be of that type parameter, e.g. the Name property becomes a property of type <>_Name
  • Each property will be public and read-only
  • For each property there will be a corresponding readonly private field
  • There will be no other properties or fields
  • There will be a constructor taking one parameter corresponding to each type parameter, in the same order as the type parameters
  • Each method and property will have the DebuggerHiddenAttribute applied to it.
  • The name of the type will start with "<>" and contain "AnonymousType"

Very little of this is guaranteed by the specification, however - so it could all change in the next version of the compiler, or if you use Mono etc.

Jon Skeet
The <> name prefix is C# only. In VB the name prefix will be "VB$AnonymousType"
JaredPar
Ooh, that's worth knowing. I dare say quite a few of the other things only apply to C# too - particularly as VB ones can be mutable. Will edit to reflect that.
Jon Skeet
I scanned the rest of the entries and there is only two other VB errors. The fields do not have the <>_ name prefix. Also the VB version has an additional private property called AtDebuggerDisplay which is used for performance reasons while debugging
JaredPar
Right. I may revise the answer at some point to have common/C#/VB sections. It'll still be brittle though :(
Jon Skeet
An even better solution would be to make anonymous types nameable. Or fix it all wit duck typing :)
JaredPar
I don't know why anyone would do it, but if the Anonymous Type that is passed in is "new {}" it will not be generic and it will have a "default" constructor.
Matthew Whited