Related
One of the nice new features of C# 7 is the possibility to define deconstructors for classes and assign the deconstructed values directly to a value tuple.
However, in the case that the object is deconstructed into a single value, I can't find a way to assign it to a tuple. Although there is a type for tuples with a single element (ValueTuple<T>), the shorthand syntax using parentheses doesn't work here. The only way I found to access the deconstructor was to call the Deconstruct method directly, but this eliminates its benefit, as I could use any method for this end.
Does anyone know a better way to deconstruct an object into a single value?
Here is my test code:
class TestClass
{
private string s;
private int n;
public TestClass(string s, int n) => (this.s, this.n) = (s, n);
public void Deconstruct(out string s) => s = this.s;
public void Deconstruct(out string s, out int n) => (s, n) = (this.s, this.n);
}
static void Main(string[] args)
{
var testObject = new TestClass("abc", 3);
var (s1) = testObject; // sytax error (comma expected)
ValueTuple<string> t = testObject; // error: "no implicit conversion from TestClass to (string)"
testObject.Deconstruct(out string s2); // this works
var (s3, n) = testObject; // no problem
Console.WriteLine($"{s1} {t.Item1} {s2} {s3} {n}");
Console.ReadKey();
}
Although there is a type for tuples with a single element (ValueTuple<T>), the shorthand syntax using parentheses doesn't work here.
That's correct. The tuple syntax only works for tuples of 2 values or more, so the Deconstruct method with only one out parameter is not very useful. (There is even a ValueTuple type for 0 elements)
The shortest solution is to just ignore the 2nd parameter:
var (s1, _) = testObject;
Edit: based on comments, a little clarification.
As of C# 7, _ is no longer a variable in this situation. It is a new feature called 'discard'.
Even if you have multiple out parameters (and even if they are different types) you can ignore any of them with an underscore:
var (s1, _, _, _) = testObject;
Deconstructions into a single element are not supported in C# 7.0.
It is unclear why you would need such a mechanism, as you can simply access a property or write a conversion operator to achieve the same thing.
Conceptually, a tuple of one element is just that one element (you don't need a tuple to hold it). So there is no tuple syntax (using parentheses notation) to facilitate that (not to mention it would be syntactically ambiguous). The same applies for deconstructions.
Here are the most relevant LDM notes I could find: 2017-03-15 (zero and one element tuples and deconstructions).
It is possible that such deconstruction could become allowed in some future recursive pattern scenarios, but that has not been finalized yet.
I decompiled some C# 7 libraries and saw ValueTuple generics being used. What are ValueTuples and why not Tuple instead?
https://learn.microsoft.com/en-gb/dotnet/api/system.tuple
https://learn.microsoft.com/en-gb/dotnet/api/system.valuetuple
What are ValueTuples and why not Tuple instead?
A ValueTuple is a struct which reflects a tuple, same as the original System.Tuple class.
The main difference between Tuple and ValueTuple are:
System.ValueTuple is a value type (struct), while System.Tuple is a reference type (class). This is meaningful when talking about allocations and GC pressure.
System.ValueTuple isn't only a struct, it's a mutable one, and one has to be careful when using them as such. Think what happens when a class holds a System.ValueTuple as a field.
System.ValueTuple exposes its items via fields instead of properties.
Until C# 7, using tuples wasn't very convenient. Their field names are Item1, Item2, etc, and the language hadn't supplied syntax sugar for them like most other languages do (Python, Scala).
When the .NET language design team decided to incorporate tuples and add syntax sugar to them at the language level an important factor was performance. With ValueTuple being a value type, you can avoid GC pressure when using them because (as an implementation detail) they'll be allocated on the stack.
Additionally, a struct gets automatic (shallow) equality semantics by the runtime, where a class doesn't. Although the design team made sure there will be an even more optimized equality for tuples, hence implemented a custom equality for it.
Here is a paragraph from the design notes of Tuples:
Struct or Class:
As mentioned, I propose to make tuple types structs rather than
classes, so that no allocation penalty is associated with them. They
should be as lightweight as possible.
Arguably, structs can end up being more costly, because assignment
copies a bigger value. So if they are assigned a lot more than they
are created, then structs would be a bad choice.
In their very motivation, though, tuples are ephemeral. You would use
them when the parts are more important than the whole. So the common
pattern would be to construct, return and immediately deconstruct
them. In this situation structs are clearly preferable.
Structs also have a number of other benefits, which will become
obvious in the following.
Examples:
You can easily see that working with System.Tuple becomes ambiguous very quickly. For example, say we have a method which calculates a sum and a count of a List<Int>:
public Tuple<int, int> DoStuff(IEnumerable<int> values)
{
var sum = 0;
var count = 0;
foreach (var value in values) { sum += value; count++; }
return new Tuple(sum, count);
}
On the receiving end, we end up with:
Tuple<int, int> result = DoStuff(Enumerable.Range(0, 10));
// What is Item1 and what is Item2?
// Which one is the sum and which is the count?
Console.WriteLine(result.Item1);
Console.WriteLine(result.Item2);
The way you can deconstruct value tuples into named arguments is the real power of the feature:
public (int sum, int count) DoStuff(IEnumerable<int> values)
{
var res = (sum: 0, count: 0);
foreach (var value in values) { res.sum += value; res.count++; }
return res;
}
And on the receiving end:
var result = DoStuff(Enumerable.Range(0, 10));
Console.WriteLine($"Sum: {result.sum}, Count: {result.count}");
Or:
var (sum, count) = DoStuff(Enumerable.Range(0, 10));
Console.WriteLine($"Sum: {sum}, Count: {count}");
Compiler goodies:
If we look under the cover of our previous example, we can see exactly how the compiler is interpreting ValueTuple when we ask it to deconstruct:
[return: TupleElementNames(new string[] {
"sum",
"count"
})]
public ValueTuple<int, int> DoStuff(IEnumerable<int> values)
{
ValueTuple<int, int> result;
result..ctor(0, 0);
foreach (int current in values)
{
result.Item1 += current;
result.Item2++;
}
return result;
}
public void Foo()
{
ValueTuple<int, int> expr_0E = this.DoStuff(Enumerable.Range(0, 10));
int item = expr_0E.Item1;
int arg_1A_0 = expr_0E.Item2;
}
Internally, the compiled code utilizes Item1 and Item2, but all of this is abstracted away from us since we work with a decomposed tuple. A tuple with named arguments gets annotated with the TupleElementNamesAttribute. If we use a single fresh variable instead of decomposing, we get:
public void Foo()
{
ValueTuple<int, int> valueTuple = this.DoStuff(Enumerable.Range(0, 10));
Console.WriteLine(string.Format("Sum: {0}, Count: {1})", valueTuple.Item1, valueTuple.Item2));
}
Note that the compiler still has to make some magic happen (via the attribute) when we debug our application, as it would be odd to see Item1, Item2.
The difference between Tuple and ValueTuple is that Tuple is a reference type and ValueTuple is a value type. The latter is desirable because changes to the language in C# 7 have tuples being used much more frequently, but allocating a new object on the heap for every tuple is a performance concern, particularly when it's unnecessary.
However, in C# 7, the idea is that you never have to explicitly use either type because of the syntax sugar being added for tuple use. For example, in C# 6, if you wanted to use a tuple to return a value, you would have to do the following:
public Tuple<string, int> GetValues()
{
// ...
return new Tuple(stringVal, intVal);
}
var value = GetValues();
string s = value.Item1;
However, in C# 7, you can use this:
public (string, int) GetValues()
{
// ...
return (stringVal, intVal);
}
var value = GetValues();
string s = value.Item1;
You can even go a step further and give the values names:
public (string S, int I) GetValues()
{
// ...
return (stringVal, intVal);
}
var value = GetValues();
string s = value.S;
... Or deconstruct the tuple entirely:
public (string S, int I) GetValues()
{
// ...
return (stringVal, intVal);
}
var (S, I) = GetValues();
string s = S;
Tuples weren't often used in C# pre-7 because they were cumbersome and verbose, and only really used in cases where building a data class/struct for just a single instance of work would be more trouble than it was worth. But in C# 7, tuples have language-level support now, so using them is much cleaner and more useful.
I looked at the source for both Tuple and ValueTuple. The difference is that Tuple is a class and ValueTuple is a struct that implements IEquatable.
That means that Tuple == Tuple will return false if they are not the same instance, but ValueTuple == ValueTuple will return true if they are of the same type and Equals returns true for each of the values they contain.
In addition to the comments above, one unfortunate gotcha of ValueTuple is that, as a value type, the named arguments get erased when compiled to IL, so they're not available for serialisation at runtime.
i.e. Your sweet named arguments will still end up as "Item1", "Item2", etc. when serialised via e.g. Json.NET.
Other answers forgot to mention important points.Instead of rephrasing, I'm gonna reference the XML documentation from source code:
The ValueTuple types (from arity 0 to 8) comprise the runtime implementation that underlies
tuples in C# and struct tuples in F#.
Aside from created via language syntax, they are most easily created via the
ValueTuple.Create factory methods.
The System.ValueTuple types differ from the System.Tuple types in that:
they are structs rather than classes,
they are mutable rather than readonly, and
their members (such as Item1, Item2, etc) are fields rather than properties.
With introduction of this type and C# 7.0 compiler, you can easily write
(int, string) idAndName = (1, "John");
And return two values from a method:
private (int, string) GetIdAndName()
{
//.....
return (id, name);
}
Contrary to System.Tuple you can update its members (Mutable) because they are public read-write Fields that can be given meaningful names:
(int id, string name) idAndName = (1, "John");
idAndName.name = "New Name";
Late-joining to add a quick clarification on these two factoids:
they are structs rather than classes
they are mutable rather than readonly
One would think that changing value-tuples en-masse would be straightforward:
foreach (var x in listOfValueTuples) { x.Foo = 103; } // wont even compile because x is a value (struct) not a variable
var d = listOfValueTuples[0].Foo;
Someone might try to workaround this like so:
// initially *.Foo = 10 for all items
listOfValueTuples.Select(x => x.Foo = 103);
var d = listOfValueTuples[0].Foo; // 'd' should be 103 right? wrong! it is '10'
The reason for this quirky behavior is that the value-tuples are exactly value-based (structs) and thus the .Select(...) call works on cloned-structs rather than on the originals. To resolve this we must resort to:
// initially *.Foo = 10 for all items
listOfValueTuples = listOfValueTuples
.Select(x => {
x.Foo = 103;
return x;
})
.ToList();
var d = listOfValueTuples[0].Foo; // 'd' is now 103 indeed
Alternatively of course one might try the straightforward approach:
for (var i = 0; i < listOfValueTuples.Length; i++) {
listOfValueTuples[i].Foo = 103; //this works just fine
// another alternative approach:
//
// var x = listOfValueTuples[i];
// x.Foo = 103;
// listOfValueTuples[i] = x; //<-- vital for this alternative approach to work if you omit this changes wont be saved to the original list
}
var d = listOfValueTuples[0].Foo; // 'd' is now 103 indeed
Hope this helps someone struggling to make heads of tails out of list-hosted value-tuples.
I don't want any sorting or anything fancy. I simply want 2 columns the left with names and the right with numbers.
Something like this:
string/int[,] myArray = new string/int[,]();
Every string will have a corresponding int. But I don't want it for sorting or anything. I know I can use a dictionary and other advanced methods which I know how to use. I want to get simple I want to see in it's simplest form how I can make an array with 2 types like this. The simplest way I can think of is to just use object and then explicitly convert later. Is there a simpler way to do this?
The simplest way to do this is to use the Tuple class. You can use Tuple with generic parameters to combine classes to form tuples. For example, Tuple<string, int> or Tuple<string, int, int?, char>. Here is documentation of the 2-parameter version. In the case you described, you probably want an instance of type Tuple<string, int>[].
You can access the elements of the Tuple using the ItemX methods: myTuple.Item1, myTuple.Item2, etc.
In order to actually create the tuples, I recommend using the Tuple.Create methods. For example: Tuple.Create("hello", 1) will return a Tuple<string, int> with the items set correctly. These Create methods allow you to omit the generic parameters.
As a side note, you mentioned that you don't need sorting. You can get arbitrary sorting rather easily by performing a LINQ query on the new Tuple<string, int> (which implements IEnumerable<Tuple<string, int>>, and so you can perform LINQ's IEnumerable extensions on it). For example, in order to order by the int part and then the `string part of the tuple, you could do:
myTupleArray.OrderBy(t => t.Item2).ThenBy(t => t.Item2);
Also look at OrderByDescending and ThenByDescending for more options.
The tuple would be a great choise like ben also said,but if you only want to work with arrays to achieve that result maybe something like this..
Array[] m = new Array[2];
m[0] = new string[10]{"2","5","7","9","12","53","11","36","39","4"};
m[1] = new int[10] { 2, 5, 7, 9, 12, 53, 11, 36, 39, 4 };
int val = (int)m[1].GetValue(3);
string str = (string)m[0].GetValue(3);
Why not use the Object class.
Object[] myarray = {string1,int1,string2,int2}
If you want to group the strings and ints you can do this:
Object[][] myarray = { {string1,int1}, {string2,int2} };
myarray[0][0] = string1 and myarray[0][1]=int1
When we declare (example) List<T> I can understand the declaration, but suppose I declare
IEnumerable<T<T1, T2>>
What did I actually declare?
Does it mean, IEnumerable<T> contains two generic types? (What is the way to use it?)
Can I have deep nested level like Person<T<T2<T3<P1,P2>>>>?
Simple example will really helpful.
If you have a class
public class Pair<T1, T2> { ... }
then you can declare a method
IEnumerable<Pair<int, string>> GetPairs();
i.e. a method that returns an enumerable of pairs where each pair consists of an int and a string.
Usage:
foreach (Pair<int, string> pair in GetPairs()) { ... }
You can also deeply nest these:
IEnumerable<Pair<int, Pair<string, string>>> GetPairs();
i.e. a method that returns an enumerable of pairs where each pair consists of an int and a pair of two strings.
This works with generics as well:
IEnumerable<Pair<T1, T2>> GetPairs<T1, T2>();
i.e. a method that returns an enumerable of pairs where each pair consists of a T1 and a T2.
But you cannot do this:
IEnumerable<T<T1, T2>> GetGenericPairs<T, T1, T2>();
Unless you've actually got a generic type called T, that won't work. You need a real type there, e.g.
IEnumerable<Dictionary<string, int>>
which is a sequence of Dictionary<string, int> references.
But yes, you can nest generics a lot - and it becomes pretty unreadable:
List<Dictionary<List<IEnumerable<string>>, Dictionary<int, int>>> aargh = null;
The above example will not compile. But you can embed Generic types within one another with something like this:
IEnumerable<IEnumerable<int>>
Which would be an enumerable of an enumerable of ints (which would act as a jagged 2 dimensional array).
(1) You declared an IEnumerable that enumerates objects of type T<T1, T2>. For example, Hashtable<Int, String>.
(2) Sure you can!
.Net 3.5 doesn't support tuples. Too bad, But not sure whether the future version of .net will support tuples or not?
I've just read this article from the MSDN Magazine: Building Tuple
Here are excerpts:
The upcoming 4.0 release of Microsoft
.NET Framework introduces a new type
called System.Tuple. System.Tuple is a
fixed-size collection of
heterogeneously typed data.
Like an array, a tuple has a fixed
size that can't be changed once it has
been created. Unlike an array, each
element in a tuple may be a different
type, and a tuple is able to guarantee
strong typing for each element.
There is already one example of a
tuple floating around the Microsoft
.NET Framework, in the
System.Collections.Generic namespace:
KeyValuePair. While KeyValuePair can be thought of as the same
as Tuple, since they are both
types that hold two things,
KeyValuePair feels different from
Tuple because it evokes a relationship
between the two values it stores (and
with good reason, as it supports the
Dictionary class).
Furthermore, tuples can be arbitrarily
sized, whereas KeyValuePair holds only
two things: a key and a value.
While some languages like F# have special syntax for tuples, you can use the new common tuple type from any language. Revisiting the first example, we can see that while useful, tuples can be overly verbose in languages without syntax for a tuple:
class Program {
static void Main(string[] args) {
Tuple<string, int> t = new Tuple<string, int>("Hello", 4);
PrintStringAndInt(t.Item1, t.Item2);
}
static void PrintStringAndInt(string s, int i) {
Console.WriteLine("{0} {1}", s, i);
}
}
Using the var keyword from C# 3.0, we can remove the type signature on the tuple variable, which allows for somewhat more readable code.
var t = new Tuple<string, int>("Hello", 4);
We've also added some factory methods to a static Tuple class which makes it easier to build tuples in a language that supports type inference, like C#.
var t = Tuple.Create("Hello", 4);
#region tuples
public class Tuple<T>
{
public Tuple(T first)
{
First = first;
}
public T First { get; set; }
}
public class Tuple<T, T2> : Tuple<T>
{
public Tuple(T first, T2 second)
: base(first)
{
Second = second;
}
public T2 Second { get; set; }
}
public class Tuple<T, T2, T3> : Tuple<T, T2>
{
public Tuple(T first, T2 second, T3 third)
: base(first, second)
{
Third = third;
}
public T3 Third { get; set; }
}
public class Tuple<T, T2, T3, T4> : Tuple<T, T2, T3>
{
public Tuple(T first, T2 second, T3 third, T4 fourth)
: base(first, second, third)
{
Fourth = fourth;
}
public T4 Fourth { get; set; }
}
#endregion
And to make declarations prettier:
public static class Tuple
{
//Allows Tuple.New(1, "2") instead of new Tuple<int, string>(1, "2")
public static Tuple<T1, T2> New<T1, T2>(T1 t1, T2 t2)
{
return new Tuple<T1, T2>(t1, t2);
}
//etc...
}
There is a proper (not quick) C# Tuple implementation in Lokad Shared Libraries (Open-source, of course) that includes following required features:
2-5 immutable tuple implementations
Proper DebuggerDisplayAttribute
Proper hashing and equality checks
Helpers for generating tuples from the provided parameters (generics are inferred by compiler) and extensions for collection-based operations.
production-tested.
Implementing Tuple classes or reusing F# classes within C# is only half the story - these give you the ability to create tuples with relative ease, but not really the syntactic sugar which makes them so nice to use in languages like F#.
For example in F# you can use pattern matching to extract both parts of a tuple within a let statment, eg
let (a, b) = someTupleFunc
Unfortunately to do the same using the F# classes from C# would be much less elegant:
Tuple<int,int> x = someTupleFunc();
int a = x.get_Item1();
int b = x.get_Item2();
Tuples represent a powerful method for returning multiple values from a function call without the need to litter your code with throwaway classes, or resorting to ugly ref or out parameters. However, in my opinion, without some syntactic sugar to make their creation and access more elegant, they are of limited use.
In my opinion, the anonymous types feature is not a tuple, but a very similar construct. The output of some LINQ Queries are collections of anonymous types, which behave like tuples.
Here is a statement, which creates a typed tuple :-) on the fly:
var p1 = new {a = "A", b = 3};
see: http://www.developer.com/net/csharp/article.php/3589916
C# 7 supports tuples natively:
var unnamedTuple = ("Peter", 29);
var namedTuple = (Name: "Peter", Age: 29);
(string Name, double Age) typedTuple = ("Peter", 29);
My open source .NET Sasa library has had tuples for years (along with plenty of other functionality, like full MIME parsing). I've been using it in production code for a good few years now.
C# supports simple tuples via generics quite easily (as per an earlier answer), and with "mumble typing" (one of many possible C# language enhancements) to improve type inference they could be very, very powerful.
For what it is worth, F# supports tuples natively, and having played with it, I'm not sure that (anonymous) tuples add much... what you gain in brevity you lose very quickly in code clarity.
For code within a single method, there are anonymous types; for code going outside of a method, I think I'll stick to simple named types. Of course, if a future C# makes it easier to make these immutable (while still easy to work with) I'll be happy.
Here's my set of tuples, they're autogenerated by a Python script, so I've perhaps gone a bit overboard:
Link to Subversion repository
You'll need a username/password, they're both guest
They are based on inheritance, but Tuple<Int32,String> will not compare equal to Tuple<Int32,String,Boolean> even if they happen to have the same values for the two first members.
They also implement GetHashCode and ToString and so forth, and lots of smallish helper methods.
Example of usage:
Tuple<Int32, String> t1 = new Tuple<Int32, String>(10, "a");
Tuple<Int32, String, Boolean> t2 = new Tuple<Int32, String, Boolean>(10, "a", true);
if (t1.Equals(t2))
Console.Out.WriteLine(t1 + " == " + t2);
else
Console.Out.WriteLine(t1 + " != " + t2);
Will output:
10, a != 10, a, True
If I remember my Computer Science classes correctly tuples are just data.
If you want grouped data - create classes that contain properties.
If you need something like the KeyValuePair then there it is.
I'd be surprised - C# is a strongly-typed language, whereas tuples are suited for more dynamically typed languages. C# has been drifting more dynamic as time goes on, but that's syntactic sugar, not a real shift in the underlying data types.
If you want two values in one instance, a KeyValuePair<> is a decent substitute, albeit clumsy. You can also make a struct or a class that'll do the same thing, and is expandable.
To make these useful in a hashtable or dictionary, you will likely want to provide overloads for GetHashCode and Equals.