How Should Anonymous Types Be Used in C#

How should anonymous types be used in C#?

Anonymous types have nothing to do with the design of systems or even at the class level. They're a tool for developers to use when coding.

I don't even treat anonymous types as types per-se. I use them mainly as method-level anonymous tuples. If I query the database and then manipulate the results, I would rather create an anonymous type and use that rather than declare a whole new type that will never be used or known outside of the scope of my method.

For instance:

var query = from item in database.Items
// ...
select new { Id = item.Id, Name = item.Name };

return query.ToDictionary(item => item.Id, item => item.Name);

Nobody cares about `a, the anonymous type. It's there so you don't have to declare another class.

What are some examples of how anonymous types are useful?

I like to use anonymous types when I need to bind to a collection which doesn't exactly fit what I need. For example here's a sample from my app:

    var payments = from terms in contract.PaymentSchedule
select new
{
Description = terms.Description,
Term = terms.Term,
Total = terms.CalculatePaymentAmount(_total),
Type=terms.GetType().Name
};

Here I then bind a datagrid to payments.ToList(). the thing here is I can aggregate multiple objects without havign to define an intermidary.

How can i initiate an anonymous type without any value in c#?

Anonymous types contain read-only properties. Therefore, if you want your object to contain properties, it is required to initialize your properties when you create them as they cannot be modified.

As mentioned here:

Anonymous types contain one or more public read-only properties.

Think of an anonymous type as a way to save on typing of defining an entire class (syntactic sugar). If you create an anonymous type without putting any info into it like the following:

var myObject = new {}

Behind the scenes the compiler create the following type:

class __Anonymous
{
public Anonymous() {}
public override bool Equals(object o) { … }
public override int GetHashCode() { … }
}

However, you cannot add properties later, which is why you need to initialize your properties when you create the anonymous type.

How to pass anonymous types as parameters?

I think you should make a class for this anonymous type. That'd be the most sensible thing to do in my opinion. But if you really don't want to, you could use dynamics:

public void LogEmployees (IEnumerable<dynamic> list)
{
foreach (dynamic item in list)
{
string name = item.Name;
int id = item.Id;
}
}

Note that this is not strongly typed, so if, for example, Name changes to EmployeeName, you won't know there's a problem until runtime.

Why use anonymous types instead of creating a class

Anonymous types are designed to be used from the scope in which they are created. No other scope should ever know about that anonymous type's definition, so since you want to be returning this object from a method, an anonymous type is not appropriate.

In general, the idea is that the object is used in just one or two places, all in the same method, and it's use is so simple and straightforward that there just is no need to create a new named type. They are also immutable, and creating immutable objects in C# is...more verbose.

How do I declare a C# anonymous type without creating an instance of it?

In fact there is no way of doing this, an anonymous object always has some object-initialization (which is by using new).

Anonymous types are some kind of set and forget, which means use them once - usually within a short piece of code e.g. a LINQ-expression- and then forget that they ever existed.

However you should ask yourself why you need this at all. When you need your list throughin your class give its entites a name. What do you gain by using the same anonymous type in different scopes? Be clear and precise. Thus every developer understands what your list contains and what he/she can accept from it.

So you´d better be off using a (private) struct for this which can also be used within your method.

class CyClass
{
private struct Person { public string Name; }

HashSet<Person> hashSet = new HashSet<Person>();

...

using (var firstScope = new Scope())
{
hashSet.Add(new Person { Name = "Boaty" });
hashSet.Add(new Person { Name = "McBoatface" });
}

using (var secondScope = new AnotherScope())
{
return names.Where(x => hashSet.Contains(new Person{ x.Name }));
}
}

MSDN clearily states this:

If you must store query results or pass them outside the method boundary, consider using an ordinary named struct or class instead of an anonymous type

However I won´t limit this to method-boundaries as described within my second paragraph.

EDIT: To answer your question if it´s possible to create an anonymous type without instantiating it, see this sentence also from MSDN:

You create anonymous types by using the new operator together with an
object initializer

EDIT2: As of C#7 you can use a tuple in your list. However a tuple has at least two properties, so your first example won´t work here:

var myList = new List<(string FirstName, string LastName)>();
myList.Add(("Boaty", "McBoatface"));

Now you can check if your other list contains such a tuple:

var contained = anotherList.Contains(("Boaty", "McBoatface"));

Get read/write properties of Anonymous Type

Anonymous types generated from C# are always immutable, so the set of writable properties is empty. In VB it's optional: each property defaults to being mutable, but if you prefix it with Key it's immutable; only properties declared using Key count for equality and hash code generation. Personally I prefer C#'s approach.

CanWrite isn't always returned as true for properties in non-anonymous types - only for writable ones. Properties can be read-only, write-only, or read-write. For example:

public class Test
{
// CanWrite will return false. CanRead will return true.
public int ReadOnly { get { return 10; } }

// CanWrite will return true. CanRead will return false.
public int WriteOnly { set {} }

// CanWrite will return true. CanRead will return true.
public int ReadWrite { get { return 10; } set {} }
}

using {...} with new to instantiate anonymous type in C#

http://msdn.microsoft.com/en-GB/library/bb397696.aspx is the MS documenation, to quote:

You create anonymous types by using the new operator together with an
object initializer. For more information about object initializers,
see Object and Collection Initializers (C# Programming Guide). The
following example shows an anonymous type that is initialized with two
properties named Amount and Message.

C#
var v = new { Amount = 108, Message = "Hello" };

This is NOT a dynamic type, this a specific static type that is 'anonymous', ie you have not given it a name. However the compiler has/will and so v is still strongly typed, you get intellisense and v.FieldIDontHave will give a compiler error.

how to refer to an item from anonymous type

var filteredResults = results.Where(r => r.ProductName == "X");

The compiler's type inference takes care of it for you. The complete answer to your question:

var customerIds = results
.Where(r => r.ProductName == "X")
.Select(r => r.CustomerId)
.Distinct()
.ToList();

or

var customerIds = (from r in results
where r.ProductName == "X"
select r.CustomerId)
.Distinct()
.ToList();

EDIT

Some musings on type inference

To select the lengths from a sequence of strings called list, you can call Select either using classic static method syntax or as an extension method:

Enumerable.Select<string, int>(list, s => s.Length)
list.Select<string, int>(s => s.Length)

Thanks to type inference, you don't need the type arguments:

Enumerable.Select(list, s => s.Length)
list.Select(s => s.Length)

In this case, the compiler can prove that the type arguments are string and int by looking at the method arguments, and it supplies these type arguments on your behalf without your having to type them into the source code.

For anonymous types, you can't provide the first type argument, because the type doesn't have a name for you to use in the source code (that's what "anonymous" means, after all: "without a name"). (You can see therefore that anonymous types and type inference were both critical -- and closely related -- prerequisites to implementing linq in the first place.)

If you check out the IL for the anonymous type example above, you'll see that the compiler has in fact given the type a name (which contains characters that are illegal in C# identifiers). When you call Select, the compiler deduces from the type of the enumerable (IEnumerable<CrazilyNamedAnonymousType>) that the first type argument should be the anonymous type, and, as with the string example, it supplies that value on your behalf.



Related Topics



Leave a reply



Submit