Reputation: 103
Is it possible to return a generic Func from a method? What I want to do is something like the GetSortFunc below.
public class Example
{
private List<MyObject> _objects;
public Example()
{
_objects = new List<MyObject>
{
new MyObject {Id = 1, Name = "First", Value = 100.0},
new MyObject {Id = 2, Name = "Second", Value = 49.99},
new MyObject {Id = 3, Name = "Third", Value = 149.99}
};
}
public void Sort(SomeEnum sortOptions)
{
_objects = _objects.OrderBy(GetSortFunc(sortOptions));
}
private Func<MyObject, TKey> GetSortFunc(SomeEnum sortOptions)
{
switch (sortOptions)
{
case SomeEnum.First:
return x => x.Id;
case SomeEnum.Second:
return x => x.Name;
case SomeEnum.Third:
return x => x.Value;
}
}
}
The SomeEnum and MyObject looks like this:
public enum SomeEnum
{
First,
Second,
Third
}
public class MyObject
{
public int Id { get; set; }
public string Name { get; set; }
public double Value { get; set; }
}
Is this possible to do or am I on the wrong track?
Upvotes: 2
Views: 699
Reputation: 171206
The problem is that the return type will vary with the type of TKey
. Also, the type parameters of OrderBy
will vary. I suggest you just duplicate the OrderBy
calls:
IEnumerable<MyObject> ApplySortOrder(IEnumerable<MyObject> items, SomeEnum sortOptions)
{
switch (sortOptions)
{
case SomeEnum.First:
return items.OrderBy(x => x.Id);
case SomeEnum.Second:
return items.OrderBy(x => x.Name);
case SomeEnum.Third:
return items.OrderBy(x => x.Value);
}
}
Alternatively, make GetSortFunc
return delegate
and call OrderBy
dynamically:
private Delegate GetSortFunc(SomeEnum sortOptions)
{
switch (sortOptions)
{
case SomeEnum.First:
return new Func<MyObject, int>(x => x.Id);
case SomeEnum.Second:
return new Func<MyObject, string>(x => x.Name);
case SomeEnum.Third:
return new Func<MyObject, int>(x => x.Value);
}
}
//...
Enumerable.OrderBy(_objects, (dynamic)GetSortFunc(sortOptions));
This would pick the right overload at runtime.
Upvotes: 3
Reputation: 13381
Simplest way fix your function change it like
private Func<MyObject, object> GetSortFunc(SomeEnum sortOptions)
{
switch (sortOptions)
{
case SomeEnum.First:
return x => x.Id;
case SomeEnum.Second:
return x => x.Name;
case SomeEnum.Third:
return x => x.Value;
default:
return x => x.Id;
}
}
Upvotes: 2
Reputation: 755179
A generic Func
, or any other generic type, can only be returned from context which has a declared generic parameter. This generic parameter needs to exist on either the method or one of the containing types of the method. In this case there is no generic parameter hence the code cannot function
This is really not a great example of a function that should be generic though. If it were generic it would need to look something like this
private Func<MyObject, TKey> GetSortFunc<TKey>(SomeEnum sortOptions)
{
switch (sortOptions)
{
case SomeEnum.First:
return x => (TKey)(object)x.Id;
case SomeEnum.Second:
return x => (TKey)(object)x.Name;
case SomeEnum.Third:
return x => (TKey)(object)x.Value;
}
}
All that ugly casting exists because the C# compiler can't find an existing conversion between int
and string
and the TKey
parameter (because it could be literally any type). Also it won't work unless the type of the property matches TKey
which is generally a sign of code that can't be generic.
Upvotes: 2