Are C# anonymous types redundant in C# 7

2019-04-05 02:18发布

问题:

Since C# 7 introduces value tuples, is there a meaningful scenario where they are better suited than tuples?

For example, the following line

collection.Select((x, i) => (x, i)).Where(y => arr[y.i].f(y.x)).ToArray();

makes the following line

collection.Select((x, i) => new {x, i}).Where(y => arr[y.i].f(y.x)).ToArray();

redundant.

What would be the use case where one is better used over the other (for either performance reasons or optimization)?

Obviously, if there is a need for more than six fields, tuples cannot be used, but is there something a bit more nuanced to it?

回答1:

There are various differences between anonymous types and C# 7 tuples, which may or may not make one more appropriate than the other in certain situations:

  • C# 7 tuples are ValueTuple<>s. That means they are value types while anonymous types are reference types.
  • Tuples allow static typing at compile time since they are a type that can be expressed explicitly. As such, you can use them as method arguments, return types, etc.
  • Members of an anonymous type are actual properties that exist on the type. Tuple items are fields.
  • The properties of an anonymous type have an actual name, while the fields on a tuple are just named ItemN (for numbers N). The labels are just metadata information that is mostly used by the compiler, and is not persisted with the actual tuple object.
  • Because creating an anonymous type actually creates a type under the hood, you have a level of type safety with them. Since tuples are just generic containers with applied type arguments, you do not have full type safety with them. For example an (int, int) tuple for a size would be fully compatible to an (int, int) tuple for a position, while anonymous types are closed off completely.
  • As Jon Skeet mentioned, the C# 7 tuple syntax is currently not supported in expression trees.


回答2:

Current answer by @poke is correct and notes differences between tuple and anonymous types. I'm going to discuss why you would still use them or prefer one over another.

There are two new c# 7 features that retires anonymous types. ValueTuples and Records.

The main reason that you would not use anonymous types is

  • you can not use anonymous types globally and they are only type safe when used locally. not being local you have to treat it as dynamic object which has significant performance overhead

Reasons that you prefer tuple over anonymous types.

  • they are type safe all over the place. (regardless of naming)

  • they can be used as method arguments, type arguments, field and pretty much every where. (yes I said pretty much, there are places that needs to adopt with tuples, its matter of time.)

  • since they can be used as type argument, you probably prefer to wrap lightweight set of parameters in single parameter. like Stack<(min, mid, max)>

  • you can change items naming when ever you feel its appropriate, in generic context name item may satisfy and in more specific context you need more specific name too, like car

  • they are implicitly convertible, int, int can be assigned to (int, long) without explicit cast.

  • they are used in Deconstructs. which brings a lot of syntactic sugar to language.

  • you can have multiple assignments and declarations like (int x, int y) = (0, 1)

Having all of this features, there is still one reason that you may prefer anonymous type over tuple.

  • Anonymous types are reference type but tuples are value type.

but what if you want to use anonymous type globally? do you prefer to have dynamic objects or statically typed objects?

The incoming Records feature again defeats anonymous types. with records you define your class in short, concise and convenient way. not a big deal. just a single line

public class Point(X, Y);

Type safety all over the place, and you also have reference type in hand. these two new features bring every thing to defeat anonymous types.

Note that Records are not added yet, we just have to wait.

Only remaining real usage of anonymous types will be

  • they still serve as backward compatible feature

  • they can be used in Linq queries when you use anonymous type locally. hence I don't say anonymous types are redundant.

As I said ValueTuples are not compatible with every component yet. its just matter of time, but this is how its going to be like in future.

enough arguments. in my humble opinion usage of anonymous types becomes rare, old programmers may still use anonymous type in Linq by habit.