2014-01-21 83 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,這通常是不能通用的代碼的標誌,否則它將不起作用。