I have a class that is used to hold values loaded from a configuration file. To make this class easier to use, I have set up many implicit conversions to some basic types.
One of the types I would like to convert to is IEnumerable(T). For example, if the programmer has a value like this in the config file
a = "1,2,3,4"
In C# code, he can write
IEnumerable<int> a = Config.a;
Ideally what I would like to write is this
public static implicit operator IEnumerable<T>(ConfigurationValue val)
{
string value = val;
string[] parts = value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
List<T> convertedTypes = new List<T>();
foreach (string part in parts)
{
T converted = Convert.ChangeType(part.Trim(), typeof(T));
convertedTypes.Add(converted);
}
return convertedTypes;
}
But this is giving me syntax errors that T is undefined. Is there no way to define such a conversion or is there a special syntax for it?
Also for the record I am using C# 4.0 in the .Net Framework 4.0
But this is giving me syntax errors that T is undefined. Is there no way to define such a conversion or is there a special syntax for it?
You're trying to declare a generic operator - and that's not supported in C#. (I don't know whether it's supported in IL.) The same is true for constructors, properties, events and finalizers.
Basically, only methods and types can be generic.
EDIT: As noted in comments, I'd write a generic method instead. User-defined conversions - particularly implicit ones - should be used very sparingly, IMO.
Instead of generic operator (which is impossible as #Jon stated) you can create extension method:
public static IEnumerable<T> AsEnumerable<T>(this string value)
{
if (String.IsNullOrEmpty(value))
yield break;
var parts = value.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries);
foreach (string part in parts)
yield return Convert.ChangeType(part.Trim(), typeof(T));
}
And use it like this:
IEnumerable<int> a = Config.a.AsEnumerable<int>();
As Jon Skeet mentioned generic operators aren't supported, but you could make it a generic extension method instead.
public static class ConfigurationExtensions
{
public IEnumerable<T> GetValues<T>(this ConfigurationValue val)
{
string value = val.Value;
string[] parts = value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
List<T> convertedTypes = new List<T>();
foreach (string part in parts)
{
T converted = (T)Convert.ChangeType(part.Trim(), typeof(T));
convertedTypes.Add(converted);
}
return convertedTypes;
}
}
Related
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 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'm playing around with a very simple program to take an array of doubles and return the standard deviation. This part worked but I wanted to make the code more reusable. I would like to make it so the method can accept a parameter of any type that could be considered numeric and return the standard deviation instead of hardcoding a double type (like I initially did in this program). How does one go about this and what is the proper term for it?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication5
{
class Program
{
static void Main(string[] args)
{
double[] avg = { 3.4, 55.6, 10.0, 4.5, 2, 2 };
double x = avg.Average();
//first round of testing
Console.WriteLine("The average of the first array is below ");
Console.WriteLine(x);
Console.WriteLine("below should be the standard deviation!");
Console.WriteLine(CalculateStandardDeviation(avg));
Console.ReadLine();
int[] intAvg = { 4, 3, 5, 6, 2 };
double secondAvg = intAvg.Average();
Console.WriteLine("The average of the second array is below ");
Console.WriteLine(secondAvg);
//this is where the error is happening
//CalculateStandardDeviation(secondAvg);
}
//this is where I tried to make the query more reusable
public static double CalculateStandardDeviation(IEnumerable<double> values)
{
double avg = values.Average();
double sum = 0;
foreach (double d in values)
{
sum += Math.Pow((d - avg), 2);
}
return Math.Pow(sum / (values.Count() - 1),.5);
}
}
}
You could use something like this:
public static decimal CalculateStandardDeviation<T>(IEnumerable<T> values)
{
IEnumerable<decimal> decimalValues = values.Select(v => Convert.ToDecimal(v));
decimal result = 0;
// calculate standard deviation on decimalValues
return result;
}
It will throw an exception if values contains values that can't be converted to a decimal, but will work if the values are of an appropriate type, and I think that makes perfect sense.
Unfortunately, there is no base class for all numbers. You can do this with a generic run-time checking method, or a compile-time safe set of overloads.
Generic Method:
public static T CalculateStandardDeviation(IEnumerable<T> values)
{
var valueArray = values.Select(Convert.ToDecimal).ToArray();
//...
return (T)standardDeviation;
}
The problem with using a single generic method is that you can't put a type constraint on the type parameter that would restrict it to only numeric types. You would have to resort to failing at run-time. There would be nothing to stop you from calling the method with an array of strings, or objects, or Colors, or HttpWebRequests, etc. and unless you do in fact know how to calculate the standard deviation of a color, you should probably stick to individual overrides for a particular numeric type:
I would recommend using the decimal type as your main implementation, and then casting everything to it.
Type-Specific Overloads:
public static decimal CalculateStandardDeviation(IEnumerable<decimal> values)
{
//...
}
public static double CalculateStandardDeviation(IEnumerable<double> values)
{
return (double)CalculateStandardDeviation(values.Select(Convert.ToDecimal));
}
public static int CalculateStandardDeviation(IEnumerable<int> values)
{
return (int)CalculateStandardDeviation(values.Select(Convert.ToDecimal));
}
// etc...
Use C# Generics.
Your function signature will be:
public static T CalculateStandardDeviation(IEnumerable<T> values)
And you can use it like:
int stdDev = CalculateStandardDeviation([int-array]);
double stdDev = CalculateStandardDeviation([double-array]);
Please follow this link:
http://msdn.microsoft.com/en-us/library/ms379564%28VS.80%29.aspx
Edit:
To resolve the Average issue on the generic types, please take a look in this library:
How to Implement Generic Method to do Math calculations on different value types
Obs: Suggestion from Brian.
EDIT
You should use JLRishe's answer, it's much more elegant than this.
You should probably start by adding generics to your method and use the type converter to transform your unknown input into doubles like so :
public static double CalculateStandardDeviation<TSource>(IEnumerable<TSource> inputs)
{
var converter = TypeDescriptor.GetConverter(typeof (double));
if (!converter.CanConvertFrom(typeof(TSource)))
return 0;
var values = new List<double>();
foreach (var value in inputs)
{
values.Add((double) converter.ConvertFrom(value));
}
// Your logic here ...
return ...;
}
I did not tested this snippet but you get the idea.
Foreword:
this answer builds on
How to verify whether a type overloads/supports a certain operator?
and
http://www.codeproject.com/Articles/87438/TinyLisp-A-Language-and-Parser-to-See-LINQ-Express
The second link shows how to compile and evaluate linq expressions.
In short you could forego static type safety and check for the ability of a type to support specific operations at runtime (first link), in case it does not you could throw an exception as the following sample demonstrates:
void Main()
{
DoAdd<float>(5,6);
DoAdd<int>(5,6);
DoAdd<bool>(true,false);
}
// Define other methods and classes here
static void DoAdd<T>(T in1, T in2){
if(!HasAdd<T>()){throw new Exception("Unsupported Type!");}
var c1 = Expression.Constant(in1, typeof(T));
var c2 = Expression.Constant(in2, typeof(T));
var expression=Expression.Add(c1, c2);
Expression<Func<T>> lExpression = Expression.Lambda<Func<T>>(expression);
Func<T> fExpression = lExpression.Compile();
Console.WriteLine(fExpression());
}
static bool HasAdd<T>() {
var c = Expression.Constant(default(T), typeof(T));
try {
Expression.Add(c, c); // Throws an exception if + is not defined
return true;
} catch {
return false;
}
}
Passing an IEnumerable of Numeric Values as a parameter to method will be supported in C# 6.0
I would like to create a Split extension that would allow me to split any string to a strongly-typed list. I have a head start, but since I was going to reuse this in many projects, I would like to get input from the community (and so you can add it to your own toolbox ;) Any ideas from here?
public static class Converters
{
public static IEnumerable<T> Split<T>(this string source, char delimiter)
{
var type = typeof(T);
//SPLIT TO INTEGER LIST
if (type == typeof(int))
{
return source.Split(delimiter).Select(n => int.Parse(n)) as IEnumerable<T>;
}
//SPLIT TO FLOAT LIST
if (type == typeof(float))
{
return source.Split(delimiter).Select(n => float.Parse(n)) as IEnumerable<T>;
}
//SPLIT TO DOUBLE LIST
if (type == typeof(double))
{
return source.Split(delimiter).Select(n => double.Parse(n)) as IEnumerable<T>;
}
//SPLIT TO DECIMAL LIST
if (type == typeof(decimal))
{
return source.Split(delimiter).Select(n => decimal.Parse(n)) as IEnumerable<T>;
}
//SPLIT TO DATE LIST
if (type == typeof(DateTime))
{
return source.Split(delimiter).Select(n => DateTime.Parse(n)) as IEnumerable<T>;
}
//USE DEFAULT SPLIT IF NO SPECIAL CASE DEFINED
return source.Split(delimiter) as IEnumerable<T>;
}
}
I'd add a parameter for the conversion function:
public static IEnumerable<T> Split<T>(this string source, Func<string, T> converter, params char[] delimiters)
{
return source.Split(delimiters).Select(converter);
}
And you can call it as
IEnumerable<int> ints = "1,2,3".Split<int>(int.Parse, ',');
I would also consider renaming it to avoid confusion with the String.Split instance method since this complicates overload resolution, and behaves differently to the others.
EDIT: If you don't want to specify the conversion function, you could use type converters:
public static IEnumerable<T> SplitConvert<T>(this string str, params char[] delimiters)
{
var converter = TypeDescriptor.GetConverter(typeof(T));
if (converter.CanConvertFrom(typeof(string)))
{
return str.Split(delimiters).Select(s => (T)converter.ConvertFromString(s));
}
else throw new InvalidOperationException("Cannot convert type");
}
This allows the conversion to be extended to other types rather than relying on a pre-defined list.
Although I agree with Lee’s suggestion, I personally don’t think it’s worth defining a new extension method for something that may trivially be achieved with standard LINQ operations:
IEnumerable<int> ints = "1,2,3".Split(',').Select(int.Parse);
public static IEnumerable<T> Split<T>
(this string source, char delimiter,Converter<string,T> func)
{
return source.Split(delimiter).Select(n => func(n)));
}
Example:
"...".Split<int>(',',p=>int.Parse(p))
Or you can use Converter.ChangeType without define function:
public static IEnumerable<T> Split<T>(this string source, char delimiter)
{
return source.Split(delimiter).Select(n => (T)Convert.ChangeType(n, typeof(T)));
}
I don't like this method. Parsing data types from strings (a sort of deserialization) is a very type- and content- sensitive process when you're dealing with data types more complex than an int. For example, DateTime.Parse parses the date using the current culture, so your method is not going to provide consistent or reliable output for dates across systems. It also tries to parse the date at all costs so it might skip through what might be considered bad input in some situations.
The goal of splitting any string into a strongly typed list cannot really be accomplished with a single method that uses hard-coded conversions, especially if your goal is broad usability. Even if you do update it repeatedly with new conversions. The best way to go about it is just to "1,2,3".Split(",").Select(x => whatever) like Douglas suggested above. It's also very clear what sort of conversion is taking place.
Part of my software is using reflection. The issue I am having is that while I can get the type of the property, I cannot convert the string value using the Type from the PropertyInfo. This is the reason why i am using t in the sample code.
The below code demonstrates the issue with the error message as a code comment. The syntax error is on the t. how can I fix this problem? thanks
class Program
{
static void Main(string[] args)
{
Type t = typeof(Letters);
Letters letter = "A".ToEnum<t>(); //-- Type or namespace expected.
}
}
public enum Letters { A, B, C }
//-- This is a copy of the EmunHelper functions from our tools library.
public static class EnumExt
{
public static T ToEnum<T>(this string #string)
{
int tryInt;
if (Int32.TryParse(#string, out tryInt)) return tryInt.ToEnum<T>();
return (T)Enum.Parse(typeof(T), #string);
}
public static T ToEnum<T>(this int #int)
{
return (T)Enum.ToObject(typeof(T), #int);
}
}
Solution:
The following works because when the value is set using reflection, the actual type of Enum is accepted. Where myObject.Letter = result is not.
Type t = currentProperty.PropertyType;
Enum result = Enum.Parse(t, #string) as Enum;
ReflectionHelper.SetProperty(entity, "LetterPropertyName", result);
Thank you all for your help.
Enum.Parse(t, #string) as Enum;
That accomplishes the same thing as the solution you posted.
To be able to call a generic method, the type must be known at compile time. Your use is invalid syntax.
To be able to call your method, you'll have to use reflection to get a reference to the correct generic function so you may call it.
public static object ToEnum(this string s, Type type)
{
var eeType = typeof(EnumExt);
var method = eeType.GetMethod("ToEnum", new[] { typeof(string) })
.MakeGenericMethod(type);
return method.Invoke(null, new[] { s });
}
Then you could call it:
Letters letter = (Letters)"A".ToEnum(t);
p.s., I strongly urge you to change your variable names to something else. Just because you can name your variables as keywords, doesn't mean that you should.
I'm not an expert with reflection, but this works:
static void Main(string[] args)
{
Type t = typeof(Letters);
MethodInfo info = typeof(EnumExt).GetMethod("ToEnum", new Type[] { typeof(string) });
var method = info.MakeGenericMethod(new Type[] { t });
var result = (Letters)method.Invoke(null, new [] { "A" });
Console.ReadLine();
}
I think your question can be understood in two ways:
i) you want to fix a syntax error
ii) you need a working implementation for the function you provide
For i), I would suggest you to change:
Letters letter = "A".ToEnum<t>()
into
Letters letter = "A".ToEnum<Letters>()
because generics are solved at compile time, hence you cannot use variables as parameters.
For ii), you may change the way you provide the type argument, from "generic" argument to "normal" argument (as proposed by Jeff Mercado). By doing so the prototype of your function becomes:
public static T ToEnum(this string #string, Type t)
I conclude with two remarks:
reflection is VERY slow to my experience. I once wrote an assembly parser making extensive use of reflection on enums for register names. It used to run for minutes (which used to make VS debugger complain about non-responsiveness) when an equivalent version without any reflection used to execute in less than 10 seconds.
as Jeff Mercado pointed out, I cannot see any good reason for you to use the same vocable for type names and variable names