Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Would .NET benefit from "named anonymous" types?

Consider this:

var me = new { FirstName = "John", LastName = "Smith" };

This is fine as we can then do this:

Console.WriteLine("{0} {1}", me.FirstName, me.LastName);

However we can't do this:

public T GetMe()
{
    return new { FirstName = "John", LastName = "Smith" };
}

because we don't know the type of T.

We could do this:

public object GetMe()
{
    return new { FirstName = "John", LastName = "Smith" };
}

but then we'd have to inspect the properties of the object using reflection in order to access them:

var p = new Prog();
object o = p.GetMe();
Type t = o.GetType();
foreach (var prop in t.GetProperties())
{
    Console.WriteLine(prop.Name + ": " + prop.GetValue(o, null));
}

However what about if we could name an anonymous type as we define it? Of course it would no longer be anonymous, however it would be more succinct and maintainable than a normal class definition.

Consider this:

public Person GetMe()
{
    return new public class Person { FirstName = "John", LastName = "Smith" };
}

The benefit being it would then be possible to return the result of a complicated Linq query from a method without having to define the class explicitly.

Consider this relatively complex Linq query:

List<int> list = new List<int>();
var query = from number in list
            select
                new
                    {
                        Number = number,
                        Square = number*number,
                        Absolute = Math.Abs(number),
                        Range = Enumerable.Range(0, number)
                    };

Instead of defining a class like so:

public class MyNumbers
{
    public int Number { get; set; }
    public int Square { get; set; }
    public int Absolute { get; set; }
    public IEnumerable<int> Range { get; set; }
}

in order to return the query variable from a method we could instead just do this:

List<int> list = new List<int>();
return from number in list
            select new public class MyNumbers
                    {
                        Number = number,
                        Square = number*number,
                        Absolute = Math.Abs(number),
                        Range = Enumerable.Range(0, number)
                    };
like image 815
Jonathan Parker Avatar asked Mar 17 '09 02:03

Jonathan Parker


People also ask

Why do we need anonymous types in C#?

Anonymous types provide a convenient way to encapsulate a set of read-only properties into a single object without having to explicitly define a type first. The type name is generated by the compiler and is not available at the source code level. The type of each property is inferred by the compiler.

Why anonymous types are better than tuples in C#?

The ValueTuple types are mutable, whereas Tuple are read-only. Anonymous types can be used in expression trees, while tuples cannot.

What is the difference between an anonymous type and a regular data type C#?

What is Anonymous Types in C#? Anonymous types in C# are the types which do not have a name or you can say the creation of new types without defining them. It is introduced in C# 3.0. It is a temporary data type which is inferred based on the data that you insert in an object initializer.

When can anonymous types be created C#?

C# Anonymous types allow us to create an object that has read only properties. Anonymous object is an object that has no explicit type. C# compiler generates type name and is accessible only for the current block of code. To create anonymous types, we must use new operator with an object initializer.


2 Answers

Actually, there's a "hack" that you can do to get an anonymous type back from a method. Consider this:

public object MyMethod()
    {
        var myNewObject = new
        {
            stringProperty = "Hello, World!",
            intProperty = 1337,
            boolProperty = false
        };

        return myNewObject;
    }

    public T Cast<T>(object obj, T type)
    {
        return (T)obj;
    }

You can now do this:

var obj = MyMethod();
var myNewObj = Cast(obj, new { stringProperty = "", intProperty = 0, boolProperty = false });

The myNewObj will now be an object of the same Type as the anonymous type.

like image 136
BFree Avatar answered Sep 30 '22 04:09

BFree


The language feature you need is:

public var GetMe()
{
    return new { FirstName = "John", LastName = "Smith" };
}

That is, var would be valid as a method return type, and the compiler would infer the actual type from whatever is returned. You would then have to do this at the call site:

var me = GetMe();

Any two anonymous types with members of the same type would be the same type, so if you wrote other functions returning the same pattern, they would have the same type. For any types A and B where B has a subset of the members of A, then A is assignment-compatible with B (B is like a base class of A). If you wrote:

public var GetMeFrom(var names)
{
    return new { FirstName = names["First"], LastName = names["Last"] };
}

The compiler would effectively define this as a generic method with two type parameters, T1 being the type of names and T2 being the type returned by the indexer on T1 that accepts a string. T1 would be constrained so that it must have an indexer that accepts a string. And at the call site you would just pass anything that had an indexer that accepted a string and returned any type you like, and that would determine the type of FirstName and LastName in the type returned by GetMeFrom.

So type inference would figure all this out for you, automatically capturing whatever type constraints are discoverable from the code.

like image 26
Daniel Earwicker Avatar answered Sep 30 '22 03:09

Daniel Earwicker