通用T与枚举和铸造T到枚举

时间:2011-09-22 01:11:30

标签: .net generics casting enums constraints

我四处搜索,找不到任何这样做的例子,虽然这很有帮助:

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。在这种情况下,性能不是问题。我以为我认为字符串工作可能很慢,而且我总是对性能提示感兴趣。

2 个答案:

答案 0 :(得分:5)

您可以使约束更严格。所有枚举都实现了可跟随的接口IFormattableIConvertibleIComparable。这将极大地限制你的原语和枚举以及类似它们的类。

或者,如果您确实想要创建仅可绑定到枚举的方法或类,则可以执行以下操作:

    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++/CLIReflection.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(虽然我爱上了它们)了解不多,但是,在这里给你一个明确的答案。