我四处搜索,找不到任何这样做的例子,虽然这很有帮助:
Create Generic method constraining T to an Enum
我有一个泛型函数,它将函数包装在API中(我无法触及)。包装函数采用System.Enum并返回相同的函数。我的通用版本在本例的非剥离版本中简化了相当多的事情。
问题是,我无法从T到System.Enum,或者再次回到原因,因为T不限于System.Enum(至少这是我的理解)。
以下代码有效,但我很想知道是否有任何隐藏的陷阱或更好的方法,因为我对泛型非常新:
using System
using System.Collections.Generic
...
public T EnumWrapper<T>(T enumVar) where T : struct, IFormattable, IConvertible, IComparable
{
if (!typeof(T).IsEnum)
throw new ArgumentException("Generic Type must be a System.Enum")
// Use string parsing to get to an Enum and back out again
Enum e = (Enum)Enum.Parse(typeof(T), enumVar.ToString());
e = WrappedFunction(e);
return (T)Enum.Parse(typeof(T), e.ToString());
}
如果可以,那就以此为例。我找不到这个,至少它是一个有效的工作方式。
P.S。在这种情况下,性能不是问题。我以为我认为字符串工作可能很慢,而且我总是对性能提示感兴趣。
答案 0 :(得分:5)
您可以使约束更严格。所有枚举都实现了可跟随的接口IFormattable
,IConvertible
和IComparable
。这将极大地限制你的原语和枚举以及类似它们的类。
或者,如果您确实想要创建仅可绑定到枚举的方法或类,则可以执行以下操作:
public abstract class InvokerHelper<T> where T : class
{
public abstract R Invoke<R>(R value) where R : struct,T;
}
public class EnumInvoker : InvokerHelper<Enum>
{
public override R Invoke<R>(R value)
{
return (R)WrappedMethod(value);
}
}
它很笨重,不能用于扩展方法,但你可以使它成为一个单例对象,然后只有泛型方法。
或者,您可以在C++/CLI
或Reflection.Emit
中编写代码,以便创建可以具有约束where T:struct,Enum
实际上你似乎只是想把一个通用的T调用一个带有枚举的方法并将它作为T右回来?
然后以下内容将起作用。
public static T WrappedMethodInvoker<T>(T value) where T:struct,IComparable,IFormattable,IConvertible
{
Enum e;
if((e = value as Enum) == null)
throw new ArgumentException("value must be an Enum")
object res = WrappedMethod(e);
return (T)res;
}
这有点容易。首先我们知道T是Enum
,你可以使用as
运算符来尝试转换为可空类型(引用类型或可空结构),Enum
肯定是。{1}}。从那里我们可以使用返回类型的协方差,WrappedMethod
返回Enum
,这意味着我们可以将它存储在一个对象中。最后,当你在泛型方法中有一个对象时,你在语法上允许将它强制转换为T.它可能会失败,但我们知道该方法返回一个相同类型的枚举。
要知道一些费用,你总是装箱和拆箱。包装方法是通用的吗?
我编辑了答案,以显示修改为示例案例的第一项技术。它非常简单和类型安全,但你必须有一个EnumInvoker来执行操作。 不幸的是,两个答案应该执行相同的操作,因为如果其参数为Enum,则调用WrappedMethod将为box值。第一种方法的唯一优点是它是强类型的,但是据我所知,泛型虚方法是最慢的调用方法。因此,避免类型检查可能不值得更容易调用。
答案 1 :(得分:3)
这里的问题很简单:C#的Type System不允许你在Enum类型上指定约束。代码没有明显的缺陷,如果你传递一个不是枚举的IConvertible结构,它不会触发编译时错误。在这种情况下,它将在运行时失败,这是不可取的,但实际上没有更好的选择。
你可能可以在编译时使用CodeContracts强制执行此操作,虽然我对CodeContracts(虽然我爱上了它们)了解不多,但是,在这里给你一个明确的答案。