价值元组与匿名类型表现

时间:2018-01-05 17:09:15

标签: c# tuples

我很惊讶这已经没有问题了。 C#7增加了值元组。 我想知道什么时候应该采用这些功能。

以此词典为例,使用匿名类型:

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());

使用这个使用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());

其中哪一个会表现得更好,使用新语法与旧语法有什么好处?

4 个答案:

答案 0 :(得分:8)

有一个非常明显的例子,您需要使用Value Tuple而不是匿名对象,以及当您需要将对象返回给调用者时。 使用public (int Count, string Hello) GetDataTuple() { return (1, "world"); } public object GetDataObject() { return new { Count = 1, Hello = "World" }; } ,您可以快速返回任意数量的命名属性,这对于匿名对象来说是不太可行的。

例如:

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

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

然后:

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

这在逻辑上也适用于类中的属性/字段:

<?php
    define('HOST','mysql.hostinger.in');
    define('USER','u400625220_user');
    define('PASS','1234567890');
    define('DB','u400625220_medi');     
    $con = mysqli_connect(HOST,USER,PASS,DB) or die('Unable to Connect');
    $SName = $_GET['SName'];
    $SAdd = $_GET['SAdd'];
    $SNum = $_GET['SNum'];
            if($SName == '' || $SAdd == '' || $SNum == '')
            {
            echo 'please fill all values';
            }
            else
            {
                $sql = "SELECT * FROM StoreRegister WHERE Store_Name = '$SName' OR Store_Address = '$SAdd' OR Store_PhoneNo = '$SNum'";
                $check = mysqli_fetch_array(mysql_query($con,$sql));
                if(isset($check))
                {
                    echo 'StoreName or Address or Phone Number already Exist'; 
                }
                else
                {
                    $sql = "INSERT INTO StoreRegister (Store_Name,Store_Address,Store_PhoneNo) VALUES('$SName','$SAdd','$SNum')";
                    if(mysqli_query($con,$sql))
                    {
                        echo 'successfully registered';
                    }
                    else
                    {
                        echo 'Please try again!'
                    }
                }
                mysqli_close($con)
            }?>

答案 1 :(得分:5)

在这种情况下,没有太大区别。

但在其他情况下,价值元组可以具有显着的性能优势。因为它们是值类型而不是引用类型,所以细心的程序员有时可以使用它们来避免在堆上分配必须也可以管理和收集的新内存。此外,值元组更容易在本地范围之外共享,因此在许多不使用匿名类型的情况下是合法的。

也就是说,值类型和引用类型也可以具有不同的语义,这意味着您可能会遇到对匿名类型的引用更为合适的情况,尤其是在您批量复制引用时。

最后,GC内存管理并不常见于程序的主要性能驱动程序。价值元组性能优势不太可能产生足够大的差异来匆忙关闭并更改所有旧代码,除非你有无限的时间花在分析器工具上以确保它是一个胜利。更值得注意哪个选择产生更清晰的代码或使用更好的语义。

答案 2 :(得分:4)

我认为基本的优势是元组有名称可以这么说;方法/属性/字段可以输入为元组。

您不能拥有匿名字段或属性(返回匿名类型,尽管可行,但并不简单,并且具有令人不舒服的限制)。

另一个重要区别是匿名类型是引用类型,而值元组是值类型。这是一个重要的区别,即使在我们只处理隐式类型本地的情况下,其中使用与示例演示的用法基本相同。

答案 3 :(得分:3)

我正在做一些研究,我找到了一个很好的基准。 Anonymous类型输出预先形成了值元组。但这只是为了做出明智决定而需要进行的众多测试之一。我只提供这个基准测试,因此没有其他人需要查看。但这并不考虑查找或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

ValueTuples采取:3426 MS

匿名类型:3137 MS

注意

如果有人想知道我决定一起避开钥匙而只是把我的词典嵌套

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()));