3

The following is just a question about the language itself, I started thinking about this before releasing a better way to architect my code but it got me interested.

If I have a method of this structure

private void Foo<T>(T bar){
    //do stuff with tuples
}

And in a different class and method, I have a variable

(int first, int second) myTuple = (1,2);

In the scope of this variable, I can do things like

var firstValue = myTuple.first;

Is there anyway I could pass myTuple down to Foo which would maintain the naming of elements within the tuple so that I could do something like bar.firstValue?

Geesh_SO
  • 2,156
  • 5
  • 31
  • 58
  • 2
    In what way *do* you want `T` to be generic? Perhaps you actually want `Foo((T1 first, T2 second) bar)`? – Jon Skeet Oct 20 '17 at 14:09
  • in `void Foo(T bar)`, `T` is a generic type, so you cannot make an assumption that `T` has the member variable `T.first`. The only way to do that is by type-check-n-cast sequence, but then you would need a type name, which seems to be anonymous here - so can't do that too – Vikhram Oct 20 '17 at 14:10
  • But your `Foo` is generic without any restrictions. How do you expect that to work? – dymanoid Oct 20 '17 at 14:10

4 Answers4

5

Through deconstruction implementation in T class, you can access instance fields using tuple. You need to provide deconstruction implementation in T class so that it will get correct value for tuple.

You can approach to you problem in following way :

  1. Provide deconstruct implementation in T class, suppose T is TestClass

    public class TestClass
    {
    
        private int _first { get; set; }
    
        private int _second { get; set; }
    
        private int _third { get; set; }
    
        public TestClass(int first, int second, int third)
        {
            _first = first;
            _second = second;
            _third = third;
        }
    
        // Implementation for tuple deconstruct
        public void Deconstruct(out int first, out int second)
        {
            first = _first;
            second = _second;
        }
    
    }
    
  2. In your Foo method, you can access in following way:

    public class Bar
    {
        public void Foo<T>(T data) where T : TestClass
        {
    
               (int first, int second) = data;
    
               //do stuff with tuples
         }
    }
    
Jules Dupont
  • 7,259
  • 7
  • 39
  • 39
Akash KC
  • 16,057
  • 6
  • 39
  • 59
5

The tuple value names are not attached to the instance but to the variable, parameter or return of a function.

This is all valid C# code:

(int a, string bx) M((int x, string y) p) => p;
// ..
(int i, string s) v1 = (j:1, k:"ome");
(int m, string n) v2 = M(v1);

For the runtime what really matters is the type of the tuple (which in the example above is always ValueTuple<int, string>). The names are just a tooling convenience provided to the reader of the code.

Paulo Morgado
  • 14,111
  • 3
  • 31
  • 59
1

you cannot use the names "first" and "second" in the Foo Method. but you can use bar.Item1 or bar.Item2.

The reson is the names "first" and "second" do not really exist - it is syntactic sougar only. the compiler accepts first and second here - but it is still a ValueTuple

Tom Söhne
  • 512
  • 2
  • 6
1

Is there anyway I could pass myTuple down to Foo which would maintain the naming of elements within the tuple so that I could do something like bar.firstValue?

The implementation of generic method is not (and should not be) dependent on what argument you pass as parameter. so T could be anything. a value type, or reference type.

constraints can only limit generic type to a more specific type. how ever you can not declare constraint for ValueTuple.

if you want to implement something that works on tuple then you need actual tuple as parameter. not generic type.

M.kazem Akhgary
  • 18,645
  • 8
  • 57
  • 118