Почему я не могу преобразовать String func(SomeEnum) в Func‹Enum, String›?

Я думаю, что это как-то связано со всей этой дисперсией, но я не совсем понимаю, почему это не разрешено.

у меня есть метод

public void method(Func<Enum, String> func)

И у меня есть несколько разных методов, таких как

public String doSomething(someEnum)
public String doSomethingElse(someOtherEnum)

Я хочу совершать такие звонки

method(doSomething)
method(doSomethingElse)

но я получаю эти ошибки

преобразовать из «группы методов» в System.Func<System.Enum,string>

По какой причине это нельзя сделать? Мне действительно нужно переписать метод в несколько методов, подобных этому?

public void method(Func<someEnum, String> func)
public void method(Func<someOtherEnum, String> func)

Это действительно некрасиво.

редактировать:

Я хочу сделать что-то подобное в методе (обратите внимание, что в моем фактическом коде enumType также передается как тип)

foreach (Enum val in Enum.GetValues(enumType))
{
      func(val);
}

person Erix    schedule 26.10.2011    source источник
comment
Это связано с тем, как Enum наследуются друг от друга ... они немного отсталые, я почти уверен, что это ограничение C #, а не CLR. У @jonskeet есть кое-что по этому поводу.   -  person Chris Pfohl    schedule 26.10.2011
comment
Что вы планируете делать с помощью этого метода? Как вы планируете передать ему параметр Enum?   -  person John Saunders    schedule 26.10.2011
comment
@JohnSaunders Я перечисляю значения перечисления внутри этого метода и вызываю func с этими значениями. Это вполне может не сработать по той же причине. Еще не зашел так далеко.   -  person Erix    schedule 26.10.2011
comment
Пожалуйста, покажите, как вы пытаетесь перечислить значения.   -  person John Saunders    schedule 26.10.2011


Ответы (4)


Вам не нужно создавать перегруженные методы, учтите:

public void method(Func<Enum, string> func) {...}
public string doSomething(MyEnum e) {...}

method((Enum e) => doSomething((MyEnum)e));

Конечно, вы несете ответственность за принуждение/кастирование по мере необходимости.

Удачного кодирования.

person Community    schedule 26.10.2011

вы, возможно, могли бы уйти с

 public void method<TEnum>(Func<TEnum, String> func)

или вы можете определить общий делегат:

 delegate String MyFunc<T>(T);

Я думаю (не пробовал) в С# 4.0 вы можете использовать совместное/контравариантное с этим:

 delegate String MyFunc1<in  T>(T);
 delegate String MyFunc2<out T>(T);

Это должно означать, что вы сможете назначить MyFunc<Derived> на MyFunc<Base>


Изменить Я только что обнаружил, что действительно ковариация не может работать для перечислений, так как вы не сможете указать ограничение типа:

delegate string Display<in T>(T v) where T : Enum;

Урожайность:

 test.cs|5 col 50 error 702| A constraint cannot be special class `System.Enum'

Итак, поскольку вы не можете получить Enum2 из Enum1, вы застряли с инвариантными общими Enums. Баггер.

person sehe    schedule 26.10.2011
comment
Спасибо за вашу попытку. Пытаюсь уложить это в голове. - person Erix; 26.10.2011

Здесь есть две проблемы:

  1. Ваше преобразование предполагает ковариантность, но Func<in T, out TResult> на самом деле контравариантно для первого универсального параметра. Вы не можете рассматривать метод, который работает с конкретным типом перечисления, как метод, который может работать с любым типом перечисления. Что, по-вашему, произойдет, если мы попытаемся вызвать делегата с каким-то другим произвольным экземпляром типа enum?

  2. Даже если вы устраните первую проблему (возможно, обратив преобразование?), это не сработает. Преобразования вариантов не хорошо сочетаются с преобразованиями бокса — преобразование из someEnum -> System.Enum является таким преобразованием. См.: Почему делегирование контравариантности не работает с типами значений? для получения дополнительной информации.

person Ani    schedule 26.10.2011

Проблема в том, что класс Enum на самом деле не тот Enum, о котором вы думаете. Enum на самом деле не является производным от [Enum], и вы не можете выразить общее ограничение как Enum.

т. е. Func<T> where T : Enum недействителен.

Лучше всего ограничить его, чтобы метод принимал только Enums:

Method<T>(Func<T, string> func) where T : struct, IConvertible

person Asti    schedule 26.10.2011