Reputation: 1349
Assume we have an input list with the following values (all are strings):
var listA = new List<string>();
listA.Add("test");
listA.Add("123");
listA.Add("5.7");
and we are also given a second list:
var listB = new List<object>();
listB.Add(typeof(string));
listB.Add(typeof(int));
listB.Add(typeof(float));
I want to verify if all values in ListA are in the right format by matching it with the list of types in ListB. Both list will have the same length.
If yes I'd like to get a List as return value where all values of ListA are stored in the format as specified in ListB. If one converion would fail I would like to be able to throw a custom exception. Something like
throw new MyException($"Failed to convert value {valueX} to {type}");
I can only imagine a very ugly solution with for loops, lots of casts/conversions and copying. Is there an elegant solution to this?
Upvotes: 2
Views: 236
Reputation: 81493
You could Zip the lists together, then use the Convert.ChangeType
Method
Returns an object of a specified type whose value is equivalent to a specified object.
It will throw an exception of the following types
InvalidCastException
This conversion is not supported. -or- value is null and conversionType is a value type. -or- value does not
implement the IConvertible interface.
FormatException
value is not in a format recognized by conversionType.
OverflowException
value represents a number that is out of the range of conversionType.
ArgumentNullException
conversionType is null.
Example
var listA = new List<string> { "test", "123", "5.7" };
var listB = new List<Type> { typeof(string), typeof(int), typeof(int) };
var combined = listA.Zip(listB, (s, type) => (Value :s, Type:type));
foreach (var item in combined)
{
try
{
Convert.ChangeType(item.Value, item.Type);
}
catch (Exception ex)
{
throw new InvalidOperationException($"Failed to cast value {item.Value} to {item.Type}",ex);
}
}
Side note: Technically speaking this is not casting per se, it's changing/converting the type
Upvotes: 1
Reputation: 18155
You could do the following with Zip.
var result = listA.Zip(listB,(value,type)=>
{
try{return Convert.ChangeType(value,(Type)type);}
catch{throw new Exception($"Cannot cast between value {value} to Type {type}");}
});
By having the conversion within the Zip, would ensure you wouldn't have to convert the whole list if there is an exception earlier in the list.
Upvotes: 1
Reputation: 4870
Ok if you want to avoid forloop
and do it with linq is still possible
Here is what i gott
var listA = new List<string>();
listA.Add("test");
listA.Add("123");
listA.Add("5.7");
var listB = new List<Type>();
listB.Add(typeof(string));
listB.Add(typeof(int));
listB.Add(typeof(float));
var index =-1;
try{
var newList = listA.Select((x, i)=> Convert.ChangeType(x, listB[(index = i)])).ToList();
}catch(Exception e){
throw new Exception("Failed to cast value "+listA[index]+" to "+listB[index]);
}
Upvotes: 0