11

I understand that anonymous types have no pre-defined type of its own. Type is assigned to it by the compiler at the compile type and details of type assigned at compile time can't be known at code level; these details are known to CLR itself. I've heard that these anonymous types at CLR are treated as if it's a reference type only. So my question is that whether at compile time a new Type like a class or a struct is created corresponding to read-only properties defined in the anonymous type?

5 Answers 5

12

I understand that anonymous types have no pre-defined type of its own.

Correct. There is no base type other than object common to anonymous types.

Type is assigned to it by the compiler at the compile type and details of type assigned at compile time can't be known at code level

That's correct.

these details are known to CLR itself.

I don't know what "details" you're talking about or what "known to CLR" means.

I've heard that these anonymous types at CLR are treated as if it's a reference type only.

You heard correctly.

So my question is that whether at compile time a new Type like a class or a struct is created corresponding to read-only properties defined in the anonymous type?

Yes. A new class is created.

Note that within an assembly if there are two anonymous types with the same property names, same property types, in the same order, then only one type is created. This is guaranteed by the language specification.

Exercise:

// Code in Assembly B:
public class B { protected class P {} }

// Code in Assembly D (references assembly B)
class D1 : B { 
  public static object M() { return new { X = new B.P() }; }
}
class D2 : B { 
  public static object M() { return new { X = new B.P() }; }
}

You are required to generate in assembly D a single class declaration that has a property X of type B.P such that D1.M().GetType() is equal to D2.M().GetType(). Describe how to do so.

Sign up to request clarification or add additional context in comments.

8 Comments

"Within the same program, two anonymous object initializers that specify a sequence of properties of the same names and compile-time types in the same order will produce instances of the same anonymous type." -(C# 4.0 specifications, 7.6.10.6)
@Xiaoy312: That's correct. Now, if you had to generate such a type for the anonymous types above in assembly D, what would that type look like if you had to write the source code?
Didn't even notice the protected keyword until now. I guess it would be something like : public abstract class CompilerMagic : B { public class AnonymousType { B.P x; public B.P X { get { return x; } } } } ?
Actually, that still doesn't work because B.P is less accessible than AT.X. And, you can't nest it under D1 or D2, as the protected property X wouldn't be available in the other class... Enlighten me, @EricLippert.
@Xiaoy312: Your objections are all correct, and yet it can be done. Hint: it could not have been done in C# 1.0.
|
6

Anonymous types are class types that derive directly from object, and that cannot be cast to any type except object. The compiler provides a name for each anonymous type, although your application cannot access it. From the perspective of the common language runtime, an anonymous type is no different from any other reference type.

Source: https://msdn.microsoft.com/en-us/library/bb397696.aspx

Comments

3

Other than having no programmer-accessible name, anonymous types are pretty straightforward: compiler generates them based on the assignments that you make, and takes care of properly merging identical anonymous types from the same method into a single run-time type.

According to C# language specification, section 7.6.10.6, anonymous types are always classes, not structs. An anonymous object initializer of the form

new { p1 = e1 , p2 = e2 , ... pn = en }

declares an anonymous type of the form

class __Anonymous1 {
    private readonly T1 f1 ;
    private readonly T2 f2 ;
    ...
    private readonly Tn fn ;
    public __Anonymous1(T1 a1, T2 a2,…, Tn an) {
        f1 = a1 ;
        f2 = a2 ;
        ...
        fn = an ;
    }
    public T1 p1 { get { return f1 ; } }
    public T2 p2 { get { return f2 ; } }
    ...
    public Tn pn { get { return fn ; } }
    public override bool Equals(object __o) { … }
    public override int GetHashCode() { … }
}

1 Comment

Though logically that is the code that is generated, that's actually a considerable simplification. See my answer for why that is.
1

These anonymous classes are derived directly from the object. Typically they are used in select LINQ queries to encapsulate read only properties into single object.

LINQ example(FirstName and LastName as FullName):

public class Person {
    public int Id {get;set;}
    public string FirstName {get;set;}
    public string LastName {get;set;}
}

IEnumerable<int> personIds = persons
    .Select(p => new { Id = p.Id, FullName = p.FirstName + " " + p.LastName})
    .Where(a => a.FullName == "John Smith")
    .Select(a => a.Id);

Comments

1

Anonymous types are a C♯ feature that has no equivalent on the CLI. They are simply compiled to normal types, with a very long and very complicated name chosen by the compiler. Note that the spec guarantees that two anonymous types with the same structure (within the same assembly) are actually the same type, so the compiler needs to take that into account, too, and only generate one type (and generate the same name for both usage sites).

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.