Reputation: 10650
essentially, exactly as in this question, but in c#.
I want to have something like this:
public IList<double> DoSomething(IList<string> strings) {
//something
}
But i'd rather have it typed such that the return value is known ahead of time so that i don't have to cast or anything outside the function. How do i do this?
Is there a generic way,
public ListType<double> DoSomething<ListType>(ListType<string> strings) where ListType : ???{
to set this up?
Upvotes: 0
Views: 60
Reputation: 191
You can use Linq to do this.
For instance if you just want to parse to double you would do:
List<double> result = strings.Select(double.Parse).ToList()
And you can send in any other method instead of double.Parse:
List<double> result = strings.Select(DoSomethingWithOneItem).ToList()
double DoSomethingWithOneItem(string item) {
//your conversion logic
}
Unfortunately there is no relation between for instance IList<TInput>
and IList<TOutput>
that can be used to help here, so you will need to specify both the input and output list type, which becomes a bit cumbersome in the general form:
IList<string> strings = new List<string> {"1.1", "2.2", "3.3"};
IList<decimal> result = strings.ConvertToSameListType((Func<string, decimal>)decimal.Parse, () => new List<decimal>());
public static class EnumerableExtensioncGeneralVersion
{
public static TOutputList ConvertToSameListType<TInputList, TOutputList, TInput, TOutput>(this TInputList source, Func<TInput, TOutput> itemConversion, Func<TOutputList> outputListConstructor)
where TInputList : IEnumerable<TInput>
where TOutputList : ICollection<TOutput>
{
TOutputList result = outputListConstructor();
foreach (TOutput convertedItem in source.Select(itemConversion))
{
result.Add(convertedItem);
}
return result;
}
}
Though you can make it much nicer to use your conversions if you just specify one extension method for each of your favourite collection types that you want to support:
//Seting up inputs
IList<string> strings = new List<string> {"1.1", "2.2", "3.3"};
IEnumerable<string> enumerableStrings = strings.Select(x => x);
ObservableCollection<string> observableStrings = new ObservableCollection<string>(strings);
//Converting
IList<decimal> resultList = strings.Convert(decimal.Parse);
IEnumerable<decimal> resultEnumerable = enumerableStrings.Convert(decimal.Parse);
ObservableCollection<decimal> observableResult = observableStrings.Convert(decimal.Parse);
public static class EnumerableExtensions
{
public static IList<TOutput> Convert<TInput, TOutput>(this IList<TInput> source, Func<TInput, TOutput> itemConversion)
{
return source.Select(itemConversion).ToList();
}
public static IEnumerable<TOutput> Convert<TInput, TOutput>(this IEnumerable<TInput> source, Func<TInput, TOutput> itemConversion)
{
return source.Select(itemConversion);
}
public static ObservableCollection<TOutput> Convert<TInput, TOutput>(this ObservableCollection<TInput> source, Func<TInput, TOutput> itemConversion)
{
return new ObservableCollection<TOutput>(source.Select(itemConversion));
}
}
Upvotes: 0
Reputation: 8498
C# does not allow exactly what you want, but the closest thing would be:
public TList2 DoSomething<TList1, TList2>(TList1 strings)
where TList1 : IEnumerable<string>
where TList2 : ICollection<decimal>, new()
{
var result = new TList2();
foreach (var s in strings)
{
result.Add(decimal.Parse(s));
}
return result;
}
and an example:
var input = new HashSet<string>(new[] { "1", "2", "3"});
List<decimal> output = DoSomething<HashSet<string>, List<decimal>>(input);
Upvotes: 2