Value Tuples Vs Anonymous Types Performance

社会主义新天地 提交于 2019-12-30 09:00:08

问题


I'm surprised there isn't a question on this already. C# 7 added value tuples. I'm trying to figure out when I should adopt these features.

Take this dictionary for example uses Anonymous Type:

var changesTypeMapByEntityState = this.ChangeTracker.Entries()
       .Where(x => (int)x.State > (int)EntityState.Unchanged)
       .GroupBy(x => new { Type = x.Entity.GetType(), x.State })
       .ToDictionary(x => x.Key, x => x.ToList());

Vs this Dictionary which uses Value Tuples

var changesTypeMapByEntityState = this.ChangeTracker.Entries()
      .Where(x => (int)x.State > (int)EntityState.Unchanged)
      .GroupBy(x => (Type: x.Entity.GetType(), x.State ))
      .ToDictionary(x => x.Key, x => x.ToList());

Which one of these would perform better, and what are the benefits of using the new syntax vs the old?


回答1:


In this situation, there's not much difference.

But in other situations value tuples can have a significant performance advantage. Because they are value types rather than reference types, a careful programmer can sometimes use them to avoid allocating new memory on the heap that must also be managed and collected. Additionally, value tuples are easier to share outside of the local scope, and so are legal in a number of situations where anonymous types are not.

That said, value types and reference types can also have different semantics, meaning you may have situations where a reference to anonymous type is much more appropriate, especially if you copy the reference around a lot.

Finally, it's not common for GC memory management to be the main performance driver of a program. The value tuple performance advantages aren't very likely to make a big enough difference to rush off and change all your old code, unless you have unlimited time to spend with a profiler tool to be sure it's a win. It's more worthwhile to be mindful of which choice produces clearer code or uses better semantics.




回答2:


There's a really obvious case where you'd use a Value Tuple instead of an anonymous objects, and that's when you need to return objects to the caller.
With the Value Tuple you have a fast way to return any number of named properties, which is not very feasible with anonymous objects.

For example:

public (int Count, string Hello) GetDataTuple()
{
    return (1, "world");
}

public object GetDataObject()
{
    return new { Count = 1, Hello = "World" };
}

Then:

var dataTuple = GetDataTuple();
Console.WriteLine(dataTuple.Count); // valid

var dataObject = GetDataObject();
Console.WriteLine(dataOjbect.Hello); // invalid

This also applies, logically, to properties/fields in classes:

class Test
{
    public (int Count, string Hello) DataTuple { get; set; } // valid
    public 'A DataObject { get; set; } // obviously invalid
}



回答3:


I’d say the basic advantage is that tuples have names so to speak; a method/property/field can be typed as a tuple.

You can’t have anonymous fields or properties (returning an anonymous type, although feasible, is not straightforward and has uncomfortable limitations).

Another important difference is that anonymous types are reference types while value tuples are value types. This is an important distinction even in scenarios where we are only addressing implicitly typed locals where usage is essentially the same as your example demonstrates.




回答4:


I was doing some research and I found a nice benchmark. The Anonymous types out preformed the value tuples. But this is just one of many test that needs to be run to make an informed decision. I'm only providing this benchmark as convenience so no one else has to look this up. But this does not account for lookups or GC Collect

    var valueTupleQuery = from i in Enumerable.Range(0, 100000)
        select (a: i, b: i, c: i, d: i, e: i, x: i, y: i + 1, z: i + 2) into x
        where x.x > 100001
        select (x: x, _: 0) into t
        where t.x.x < 0
        select t.x;

    var anonymousQuery = from i in Enumerable.Range(0, 100000)
        select new { a = i, b = i, c = i, d = i, e = i, x = i, y = i + 1, z = i + 2 } into x
        where x.x > 100001
        select (x: x, _: 0) into t
        where t.x.x < 0
        select t.x;

    var stopwatch = new Stopwatch();

    stopwatch.Restart();
    for (var i = 0; i < 1000; i++)
    {
        valueTupleQuery.ToArray();
    }
    stopwatch.Stop();

    Console.WriteLine(stopwatch.ElapsedMilliseconds);

    stopwatch.Restart();
    for (var i = 0; i < 1000; i++)
    {
        anonymousQuery.ToArray();
    }
    stopwatch.Stop();

    Console.WriteLine(stopwatch.ElapsedMilliseconds);

Ran on lenovo y700

The ValueTuples took: 3426 MS

Anonymous Types took: 3137 MS

NOTE

In case anyone was wondering I decided to avoid the key all together and just nests my dictionaries

var changesTypeMapByEntityState = this.ChangeTracker.Entries()
      .Where(x => (int)x.State > (int)EntityState.Unchanged)
      .GroupBy(x => x.Entity.GetType())
      .ToDictionary(x => x.Key, 
                    x => x.GroupBy(g => g.State)
                        .ToDictionary(k => k.Key, v => v.ToList()));


来源:https://stackoverflow.com/questions/48118187/value-tuples-vs-anonymous-types-performance

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!