Swojego czasu Procent zwrócił uwagę na możliwość dokonywania konwersji pomiędzy typami za pomocą TypeConverter, który znajduje się w BCL.
W jednym z małych podprojektów musiałem dokonać konwersji parametrów przekazywanych jako lista wartości określonego typu rozdzielona przecinkami. Dokładnie mówiąc ktoś mógł wpisać w command line:
program.exe -o -action add -values ola,ma,kota,a,kto,ma,ole
Dzięki konstrukcji Command Line Parser wiedziałem, że o jest poleceniem, nazwa klasy implementująca to polecenie to OCommand. Klasa ta posiada takie własności jak Add i Values. Add jest enumeratorem zaś Values jest generyczną listą stringów. Skoro już coś wiemy, to teraz trzeba było znaleźć rozwiązanie problemu – jak przekonwertować wartości aby stały się generyczną listą stringów?
Dodatkowo chciałem mieć pewność, iż każdy parametr kolekcji przekazanej jest danego typu – czyli należało sprawdzić każdą wartość przekazaną w atrybucie values czy jest typu string. Żeby jednak nie robić czegoś hardcoded, chciałem to zrobić tak by było to uniwersalne – przekazanie wartości int, datetime itp. itd.
Pierwszym krokiem było dostanie się do PropertyDescriptor danej własności:
var property = ( from prop in properties where string.Compare(prop.Name, dumpKeyValue.Key, true) == 0 || prop.GetAttribute<ParameterAttribute>().ShortName == dumpKeyValue.Key || prop.Name == "CommandName" select prop ).FirstOrDefault();
Kiedy już miałem property to mogłem działać dalej:
object valueForProp;
switch (property.PropertyType.Name)
{
	case "List`1":
	case "IList`1":
		MethodInfo methodInfo = typeof(StringEx).GetMethod("GetListFromCommaSeparatedValues", BindingFlags.Static | BindingFlags.NonPublic);
		Type[] genericArguments = property.PropertyType.GetGenericArguments();
		MethodInfo genericMethodInfo = methodInfo.MakeGenericMethod(genericArguments);
		valueForProp = genericMethodInfo.Invoke(null, new object[] { keyValuePair.Value });
		break;
	// other cases
	default:
		// ...
		break;
}
// valueForProp check
property.SetValue(currentCommand, valueForProp);
Dzięki prostemu switch jestem wstanie wykryć, kiedy używam generycznej listy, następnie za pomocą typu własności wyciągnąć informacje na temat generycznego typu listy i stworzyć generyczną definicję metody, którą potem można wywołać.
Sama metoda GetListFromCommaSeparatedValues jest Extension Method na wartości string:
public static List<T> GetListFromCommaSeparatedValues<T>(this string commaSeparatedValues)
{
	var list = new List<T>();
	// pobieramy konwerter dla danego typu
	TypeConverter typeConverter = TypeDescriptor.GetConverter(typeof(T));
	// sprawdzamy czy można wykonać konwersję za pomocą wartości string
	if (!typeConverter.CanConvertFrom(typeof(string)))
	{
		return list;
	}
	// każdą wartość rodzieloną przecinkiem dodaj do listy wynikowej
	foreach (var value in commaSeparatedValues.Split(','))
	{
		list.Add((T)typeConverter.ConvertFromInvariantString(value.Trim()));
	}
	return list;
}
Prosty zabieg a dzięki niemu mogę podawać wartości w dowolnym typie, który może zostać przekonwertowany z wartości stringowej.











 
        


