C# generic enum приведение к определенному перечислению
у меня есть общий метод, который принимает "T" type
и это перечислитель. Внутри метода я должен вызвать вспомогательные методы класса и depands имени метода по типу перечислителя.
public Meth<T> (T type) {
if (typeof(T) == typeof(FirstEnumType)) {
FirstEnumType t = ??? // I somehow need to convert T type to FirstEnumType
this.helperFirstCalcBll(t);
}
else
{
SecondEnumType t = ??? // I somehow need to convert T type to SecondEnumType
this.helperSecondCalcBll(t);
}
}
4 ответов
нет допустимого приведения от произвольного типа к типу перечисления, поэтому это не разрешено. Сначала вам нужно бросить объект:
FirstEnumType t = (FirstEnumType)(object)type;
это "трюки" компилятора путем передачи в object
(что всегда допустимо), затем вниз-приводит к типу перечисления. Предполагая, что вы выполнили проверку типа среды выполнения, downcast никогда не завершится неудачей. Однако реализация этого в ветке else, как указано, не гарантируется.
можно было бы спросить, почему метод даже общий в во-первых, но именно так вы можете заставить этот конкретный метод работать.
public void Meth(FirstEnumType type) {
this.helperFirstCalcBll(type);
}
public void Meth(SecondEnumType type) {
this.helperSecondCalcBll(type);
}
это нечто dynamic
очень полезно:
public void Meth<T>(T enumValue) where T : struct
{
InternalMeth((dynamic)enumValue);
}
private void InternalMeth(FirstEnumType enumValue)
{
this.helperFirstCalcBll(enumValue);
}
private void InternalMeth(SecondEnumType enumValue)
{
this.helperSecondCalcBll(enumValue);
}
private void InternalMeth(object enumValue)
{
// Do whatever fallback you need
}
это позволяет избежать необходимости писать все эти if (typeof(T) == typeof(...))
и все - вы позволяете динамической диспетчерской обрабатывать выбор лучшей перегрузки во время выполнения. The object
перегрузка существует, если все остальные терпят неудачу, так что вы можете, например, бросить исключение.
попробуйте определить вспомогательный метод:
private TOutput Convert<TInput, TOutput>(TInput value)
where TInput : struct
where TOutput : struct
{
var matchingValues = Enum.GetValues(typeof(TOutput))
.Cast<int>()
.Where(v => System.Convert.ToInt32(value) == v);
if(!matchingValues.Any())
{
var message = String.Format("No matching value found in enum '{0}' for value '{1}'.", typeof(TOutput).Name, value);
throw new ArgumentException(message);
}
var obj = (object)matchingValues.Single();
return (TOutput)obj;
}
это преобразует значения двух перечислений, учитывая, что в выходном перечислении есть значение, равное входному значению.
и в вашем коде вы бы назвали это следующим образом:
public Meth<T> (T type)
{
if (typeof(T) == typeof(FirstEnumType))
{
FirstEnumType t = Convert(type);
this.helperFirstCalcBll(t);
}
else
{
SecondEnumType t = Convert(type);
this.helperSecondCalcBll(t);
}
}