I have an Option<T> that works great for any type that be converted from string, and now I am trying to extend that to cover Option<T[]> (ie, Option<int[]>). Afraid I may be coming at this problem with too many C++ templates under my belt. Having trouble wrapping my head around the seemingly inadequate C# generics. I can detect when T is an array, but then I can't make any use of typeof(T).GetElementType().
I think I may be in one of those XY problem valleys, where I am just coming at this from the wrong direction and can't see the path over the rise. Any ideas how to get unbocked? I've tried everything I can think of and spend the past couple of days trying to figure out to get unblocked. I would add that I can arrange to parse the comma delimited string into an array of strings prior to conversion. The code below is a simplified extract from some of what I've tried.
using System;
using System.Collections.Generic;
namespace StackOverflowCS
{
internal static class ConversionExtensionMethods
{
internal static T ChangeType<T>(this object obj)
{
try
{
return (T)Convert.ChangeType(obj, typeof(T));
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
internal static T ChangeType<T>(this object[] objects)
{
try
{
if (!typeof(T).IsArray) throw new Exception("T is not an array type.");
var converted = new object[objects.Length];
foreach (var item in objects)
{
// AFAIK, converstion requires compile time knowledge of T.GetElementType(),
// but this won't compile.
converted.Add(item.ChangeType<typeof(T).GetElementType())>
}
return (T)converted; // And this won't compile either.
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
}
internal class Option<T>
{
public T Value;
public Option() {}
// This works fine for non-arrays
public bool SetValue(string valueString)
{
try
{
Value = valueString.ChangeType<T>();
}
catch (Exception e)
{
Console.WriteLine(e);
return false;
}
return true;
}
// I think I am in an XY problem valley here.
public bool SetValue(string[] valueStrings)
{
try
{
if (!typeof(T).IsArray)
{
throw new Exception("T is not an array type.");
}
// The crux of my problem is I can't seem to write pure generic code in C#
var convertedElements = new List<!!!Cannot use typeof(T).GetElementType() here!!!>();
foreach (var item in valueStrings)
{
// The crux of my problem is I can't seem to write pure generic code in C#
convertedElements.Add(!!!Cannot use typeof(T).GetElementType() here!!!);
}
}
catch (Exception e)
{
Console.WriteLine(e);
return false;
}
return true;
}
}
public class Program
{
static void Main(string[] args)
{
var opt = new Option<int>(); // Works fine.
var integerList = new Option<int[]>();
integerList.SetValue("this,that,whatever"); // This fails at run-time.
foreach (var item in integerList.Value)
{
Console.WriteLine(item);
}
Console.ReadKey();
}
}
}
The parser (not shown) can detect arguments of the form
Opt:1,2,3 or
Opt:"short sentence",word,"string with quotes\" in it", etc.
I'd rather not have the parser try to figure out what type the Opt Option's array elements are. The Option<T>.SetValue(string[] strings) function should be able to handle that.
I haven't even tried test/implement `Options<List> yet, though I suspect that would be much easier.
integerList.SetValue("1,2,NotANumber");Should the array contains 1 and 2, or should it be null (or uninitialized)? Fourth, What if the string is delimited using;or ` ` (space) or|or whatever other char the user of your code thinks is a good delimiter?integerList.SetValue("this,that,whatever");will call this overload:SetValue(string valueString)- you probably meant to useSetValue(string[] valueString)which means you have to do something like this:integerList.SetValue(new [] {"this","that","whatever"});