Practical example where Tuple can be used in .Net 4.0?

后端 未结 19 656
后悔当初
后悔当初 2020-12-04 07:44

I have seen the Tuple introduced in .Net 4 but I am not able to imagine where it can be used. We can always make a Custom class or Struct.

相关标签:
19条回答
  • 2020-12-04 08:10

    With tuples you could easily implement a two-dimensional dictionary (or n-dimensional for that matter). For example, you could use such a dictionary to implement a currency exchange mapping:

    var forex = new Dictionary<Tuple<string, string>, decimal>();
    forex.Add(Tuple.Create("USD", "EUR"), 0.74850m); // 1 USD = 0.74850 EUR
    forex.Add(Tuple.Create("USD", "GBP"), 0.64128m);
    forex.Add(Tuple.Create("EUR", "USD"), 1.33635m);
    forex.Add(Tuple.Create("EUR", "GBP"), 0.85677m);
    forex.Add(Tuple.Create("GBP", "USD"), 1.55938m);
    forex.Add(Tuple.Create("GBP", "EUR"), 1.16717m);
    forex.Add(Tuple.Create("USD", "USD"), 1.00000m);
    forex.Add(Tuple.Create("EUR", "EUR"), 1.00000m);
    forex.Add(Tuple.Create("GBP", "GBP"), 1.00000m);
    
    decimal result;
    result = 35.0m * forex[Tuple.Create("USD", "EUR")]; // USD 35.00 = EUR 26.20
    result = 35.0m * forex[Tuple.Create("EUR", "GBP")]; // EUR 35.00 = GBP 29.99
    result = 35.0m * forex[Tuple.Create("GBP", "USD")]; // GBP 35.00 = USD 54.58
    
    0 讨论(0)
  • 2020-12-04 08:10

    C#'s tuple syntax is ridiculously bulky, so tuples are painful to declare. And it doesn't have pattern matching, so they're also painful to use.

    But occasionally, you just want an ad-hoc grouping of objects without creating a class for it. For example, let's say I wanted to aggregate a list, but I wanted two values instead of one:

    // sum and sum of squares at the same time
    var x =
        Enumerable.Range(1, 100)
        .Aggregate((acc, x) => Tuple.Create(acc.Item1 + x, acc.Item2 + x * x));
    

    Instead of combining a collection of values into a single result, let's expand a single result into a collection of values. The easiest way to write this function is:

    static IEnumerable<T> Unfold<T, State>(State seed, Func<State, Tuple<T, State>> f)
    {
        Tuple<T, State> res;
        while ((res = f(seed)) != null)
        {
            yield return res.Item1;
            seed = res.Item2;
        }
    }
    

    f converts some state into a tuple. We return the first value from the tuple and set our new state to the second value. This allows us to retain state throughout the computation.

    You use it as such:

    // return 0, 2, 3, 6, 8
    var evens =
        Unfold(0, state => state < 10 ? Tuple.Create(state, state + 2) : null)
        .ToList();
    
    // returns 0, 1, 1, 2, 3, 5, 8, 13, 21, 34
    var fibs =
        Unfold(Tuple.Create(0, 1), state => Tuple.Create(state.Item1, Tuple.Create(state.Item2, state.Item1 + state.Item2)))
        .Take(10).ToList();
    

    evens is fairly straightforward, but fibs is a little more clever. Its state is actually a tuple which holds fib(n-2) and fib(n-1) respectively.

    0 讨论(0)
  • 2020-12-04 08:14

    You should be very careful with using Tuple and probably think twice before do this. From my previous experience I found out that using Tuple makes code very difficult to read and support in the future. A while ago, I had to fix some code where tuples were used almost everywhere. Instead of thinking about proper object models, they just used tuples. That was nightmare... sometimes I wanted to kill the guy who wrote the code...

    Don't want to say that you shouldn't use Tuple and it's evil or something and I'm hundred percent sure there are some tasks where the Tuple is the best candidate to be used, but probably you should think again, do you REALLY need it?

    0 讨论(0)
  • 2020-12-04 08:16

    I tend to avoid Tuple for most scenarios since it hurts readability. However, Tuple is useful when you need to group unrelated data.

    For example, suppose you have a list of cars and the cities in which they were purchased:

    Mercedes, Seattle
    Mustang, Denver
    Mercedes, Seattle
    Porsche, Seattle
    Tesla, Seattle
    Mercedes, Seattle
    

    You want to aggregate the counts for each car per city:

    Mercedes, Seattle [3]
    Mustang, Denver [1]
    Porsche, Seattle [1]
    Tesla, Seattle [1]
    

    To do this, you create a Dictionary. You have a few options:

    1. Create a Dictionary<string, Dictionary<string, int>>.
    2. Create a Dictionary<CarAndCity, int>.
    3. Create a Dictionary<Tuple<string, string>, int>.

    Readability is lost with the first option. It will require you to write a lot more code.

    The second option works and is succinct, but car and city aren't really related and probably don't belong in a class together.

    The third option is succinct and clean. It's a good use of Tuple.

    0 讨论(0)
  • 2020-12-04 08:16

    Only for prototyping - Tuples are meaningless. It convenient to use them but it's a shortcut only! For prototypes - fine. Just be sure to delete this code later.

    It easy to write, hard to read. It has no visible advantages over classes, inner classes , anonymous classes etc.

    0 讨论(0)
  • 2020-12-04 08:20

    Just found the solution of one of my issues in Tuple. It is like declaring a class in scope of a method, but with lazy declaration of its fields names. You operate with collections of tuples, its single instances and then create a collection of anonymous type with the required field names, basing on your tuple. This avoids you from creating the new class for this purpose.

    The task is to write a JSON response from LINQ without any additional classes:

     //I select some roles from my ORM my with subrequest and save results to Tuple list
     var rolesWithUsers = (from role in roles
                           select new Tuple<string, int, int>(
                             role.RoleName, 
                             role.RoleId, 
                             usersInRoles.Where(ur => ur.RoleId == role.RoleId).Count()
                          ));
    
     //Then I add some new element required element to this collection
     var tempResult = rolesWithUsers.ToList();
     tempResult.Add(new Tuple<string, int, int>(
                            "Empty", 
                             -1,
                             emptyRoleUsers.Count()
                          ));
    
     //And create a new anonimous class collection, based on my Tuple list
     tempResult.Select(item => new
                {
                    GroupName = item.Item1,
                    GroupId = item.Item2,
                    Count = item.Item3
                });
    
    
     //And return it in JSON
     return new JavaScriptSerializer().Serialize(rolesWithUsers);
    

    Of cause we could do this with declaring a new Class for my groups, but the idea to create such an anonimous collections without declaring of new classes.

    0 讨论(0)
提交回复
热议问题