C# .NET Create KeyValuePairs and Tuples the Easy Way 'a'.Tpl("ABC")
More with Extension Methods and Implied Generic Arguments
I have previously written an article entitled "C# .NET -- Implied Generics in Extension Methods:
A Really Cool Way to Raise Events". This new article extends upon that to easily create Tuple
objects and KeyValuePair
structs.
As you may recall from the mentioned article, the C# compiler has a really awesome ability to infer the correct type to use for a generic parameter based upon the data type that is passed in. That functionality, however, is in fact available to any static generic method; by definition, an extension method is always static. And, it is that ability that allows things like the static Tuple.Create()
method to work.
Consider the following code snips. They are functionally the same;they all create an object of type Tuple<char,string>
and assign the newly create instance.
Tuple<char, string> tuple1 = new Tuple<char,string>('a', "xyz");
var tuple2 = new Tuple<char,string>('a', "xyz");
var tuple3 = Tuple.Create<char,string>('a', "xyz");
var tuple4 = Tuple.Create('a', "XYZ");
In that example, tuple1
and tuple2
are created via the exact same executable code. The var
keyword is just "syntax candy" -- it just makes it easier to write code without affecting the actual IL that is created by the compiler. Therefore, in the case of tuple2
, the compiler is able to figure out the variable type (including the generic parameters) and substitute Tuple<char,string>
for var
at compile time.
The variable tuple3
, however is created via a slightly different mechanism. It calls into the Tuple.Create<T1, T2>(T1 v1, T2 v2)
static method, explicitly specifying T1 = char
and T2 = string
. The variable tuple4
is created via that exact same static method, but uses implied generic parameters to infer that T1 = char
(because of 'a'
) and T2 = string
(because of "xyz"
).
The way in which tuple4
was created is definitely the shortest way to create the variable presented in those examples above. However, it is still somewhat verbose, especially if you want to do something line pass multiple tuples into a method that has a params
argument of tuples.
public void MyMethod(
params Tuple<char,string>[] tuples)
{
foreach (var tuple in tuples)
{
// Do something
}
}
Then, elsewhere the tuples could be passed into MyMethod
using something like this:
// Can do this
MyMethod(
new Tuple<char, string>('a', "XYZ"),
new Tuple<char, string>('b', "UVW"),
new Tuple<char, string>('c', "RST")
);
// Or, can do this if you don't want to specify the generic template parameter types
MyMethod(
Tuple.Create('a', "XYZ"),
Tuple.Create('b', "UVW"),
Tuple.Create('c', "RST")
);
But, with a little but of extension method magic, that can be shorted to something more like this:
MyMethod(
'a'.Tpl("XYZ"),
'b'.Tpl("UVW"),
'c'.Tpl("RST")
);
To do that, you need to create a really simple extension method, Tpl
, that uses implied generic template parameters. While you at it, you should probably just create a Kvp
extension method for KeyValuePair
as well!
var myKeyValuePair = 'd'.Kvp("OPQ");
One possible implementation of these extension methods is shown below. And, of course you can easily add more Tpl
methods that take additional generic parameters.
public static class MyExtensionMethods
{
public static KeyValuePair<T1, T2> Kvp<T1, T2>(
this T1 key,
T2 value)
{
return new KeyValuePair<T1, T2>(key, value);
}
public static Tuple<T1, T2> Tpl<T1, T1>(
this T1 v1,
T2, v2)
{
return new Tuple<T1, T2>(v1, v2);
}
....
public static Tuple<T1, T2, T3, T4, T5, T6, T7> Tpl<T1, T2, T3, T4, T5, T6, T7>(
this T1 v1,
T2 v2,
T3 v3,
T4 v4,
T5 v5,
T6 v6,
T7 v7)
{
return new Tuple<T1, T2, T3, T4, T5, T6, T7>(v1, v2, v3, v4, v5, v6, v7);
}
}
Programmer, Engineer