2014-01-21 4 views
2

Возможно ли вернуть общий Func из метода? Я хочу сделать что-то вроде GetSortFunc ниже.метод return generic func 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# компилятор не может найти существующее преобразование между int и string и параметром TKey (потому что это может быть буквально любым тип). Также он не будет работать, если тип свойства не соответствует TKey, который обычно является признаком кода, который не может быть общим.

Смежные вопросы