2014-01-21 59 views
2

是否有可能从方法返回一个通用的Func? 我想要做的就像下面的GetSortFunc。方法返回通用函数c#

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; 
     } 
    } 
} 

的SomeEnum和myObject的是这样的:

public enum SomeEnum 
{ 
    First, 
    Second, 
    Third 
} 

public class MyObject 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public double Value { get; set; } 
} 

这是可以做到的还是我在错误的轨道上?

+2

是的有可能:-) – Grundy

+0

看起来它会少了很多的工作,你只使用'.OrderBy()',因为它是 – Alex

+0

首先,这是可能的,其次,是否可能,你可以编译你的代码并找出答案。 –

回答

2

最简单的方法解决您的功能改变它像

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; 
    } 
} 
+0

很明显!我现在觉得有点愚蠢,因为没有想到这个:) – doktron

+0

似乎工作。我认为运行时可以确定该对象实际上是类型int/string/double – doktron

+0

我不知道这会工作。它似乎尝试投射到IComparable或类似的东西。 – usr

3

问题是返回类型将随着TKey的类型而变化。此外,OrderBy的类型参数也会有所不同。我建议你刚才复制OrderBy电话:

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); 
    } 
} 

或者,让GetSortFunc返回delegate和动态调用OrderBy

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)); 

这将挑选合适的过载运行时。

+0

不是所有的代码路径返回值:-) – Grundy

+0

谢谢!我可能会用第二个例子,因为我将不得不在OrderBy和OrderByDescending之间切换,这会使第一个方法变得有点混乱 – doktron

+0

编译器不喜欢动态方法,他说扩展方法不能动态调度 – doktron

2

通用Func或任何其他泛型类型只能从具有声明泛型参数的上下文返回。该通用参数需要存在于该方法的一个或一个包含类型的方法中。在这种情况下没有通用参数,因此代码不能运行

这实际上不是一个应该是通用函数的好例子。如果是一般的就需要这个样子

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; 
    } 
} 

所有这些丑陋铸造的存在是因为C#编译器不能找到intstringTKey参数(之间现有的转换,因为它可能是几乎任何类型)。除非属性的类型匹配TKey,这通常是不能通用的代码的标志,否则它将不起作用。