I would create some listing of custom parsers that you register then later leverage since you seem to be wanting to use custom rules anyway:
public static class StringParsers
{
private static Dictionary<Type, object> Parsers = new Dictionary<Type, object>();
public static void RegisterParser<T>(Func<string, T> parseFunction)
{
Parsers[typeof(T)] = parseFunction;
}
public static T Parse<T>(string input)
{
object untypedParser;
if (!Parsers.TryGetValue(typeof(T), out untypedParser))
throw new Exception("Could not find a parser for type " + typeof(T).FullName);
Func<string, T> parser = (Func<string, T>)untypedParser;
return parser(input);
}
}
During your application initialization, you would register the types you intend to use later in your application (I'm guessing this is known since you're using generics):
StringParsers.RegisterParser<string[]>(input => input.Split(','));
StringParsers.RegisterParser<int[]>(input => input.Split(',').Select(i => Int32.Parse(i)).ToArray());
StringParsers.RegisterParser<int>(input => Int32.Parse(input));
Finally, you can call it simply:
string testArrayInput = "1,2,8";
int[] integers = StringParsers.Parse<int[]>(testArrayInput); // {1, 2, 8}
string[] strings = StringParsers.Parse<string[]>(testArrayInput); // {"1", "2", "8"}
int singleInt = StringParsers.Parse<int>("9999"); //9999
Now, this is a pretty simple implementation. You may wish to extend it so instead of using type Func<string, T> it might use an IStringParser interface and you can provide deeper implementations of the parsing if necessary. Furthermore, you may wish to make it thread safe (unless you're sure that won't be an issue, or if you are sure your registration on startup is before any usages)
EDIT: If you really, really, really want it all in one function just accounting for your comma delimited array, then you can use this:
public static T Str2Val<T>(string str)
{
if (!typeof(T).IsArray)
return (T)Convert.ChangeType(str, typeof(T));
Type elementType = typeof(T).GetElementType();
string[] entries = str.Split(',');
int numberOfEntries = entries.Length;
System.Array array = Array.CreateInstance(elementType, numberOfEntries);
for(int i = 0; i < numberOfEntries; i++)
array.SetValue(Convert.ChangeType(entries[i], elementType), i);
return (T)(object)array;
}
But this feels so wrong. There must be a better way and to avoid the double generic input in Alexander's answer, but there you go.
char[]? useToCharArray.int[]? How are you going to split it: comma, dash, dot?int[]tostring?T == int[]I'm trying to convertstringtoint[], like"1,2,3"to{1, 2, 3}.TimplementsIConvertible. Otherwise, there's no hope it will succeed withConvert.ChangeType. You could do like this:if (typeof(IConvertible).IsAssignableFrom(typeof(T))) { return (T)Convert.ChangeType(str, typeof(T)); } /* otherwise, check if T is a collection, and so on. */.