【问题标题】:Calling a method by enum Attribute in C#C#中通过枚举属性调用方法
【发布时间】:2014-08-15 08:28:03
【问题描述】:

首先,我很抱歉,因为我的问题很愚蠢。但我希望有人能在这种方法上帮助我。

我有一个枚举,我想按照描述添加新的魔法属性:

public enum FunctionType
    {
        [CallMethod(ExecuteFunction.DOPLUS)] //How to implement CallMethod magic attribute
        PLUS,
        [CallMethod(ExecuteFunction.DOMINUS)]
        MINUS,
        [CallMethod(ExecuteFunction.DOMULTIPLY)]
        MULTIPLY,
        [CallMethod(ExecuteFunction.DODIVIDE)]
        DIVIDE
    }

我的班级有这样的 FunctionType 属性:

public class Function
    {
        private FunctionType _functionType;

        public List<object> Params
        { get; set; }

        public FunctionType FunctionType
        {
            get { return _functionType; }
            set { _functionType = value; }
        }

        public string Execute()
        {
            return SomeMagicMethod(this.FunctionType); //How to implement this method to return my result as expected
        }
    }

最后,我的计算类有一些函数返回结果:

public static class ExecuteFunction
    {
        public static string DOPLUS(int a, int b)
        {
            return (a + b).ToString();
        }

        public static string DOMINUS(int a, int b)
        {
            return (a - b).ToString();
        }

        public static string DOMULTIPLY(int a, int b)
        {
            return (a * b).ToString();
        }

        public static string DODIVIDE(int a, int b)
        {
            return (a / b).ToString();
        }
    }

我的愚蠢问题是:如何在上面的枚举和 SomeMagicMethod 中实现 CallMethodAttribute 以运行指定的方法而不像往常一样使用 switch case?

【问题讨论】:

  • 暂时忘记 calling 部分 - 您的属性现在根本无法编译,因为该属性的参数必须是编译时常量几个受支持类型之一的值。不过,您可以有一个 string 来指定方法的名称。顺便说一句,我强烈建议遵循 .NET 命名约定 - 去掉那些喧闹的名字。

标签: c# reflection enums


【解决方案1】:

你不能像你写的那样在一个属性中引用一个方法(它不是编译时的)。

您的方法是错误的 - 您应该使用引用其对应枚举的属性来装饰方法,如下所示:

public static class ExecuteFunction
{
    [CallMethod(FunctionType.PLUS)]
    public static string DOPLUS(int a, int b)
    {
        return (a + b).ToString();
    }

    [CallMethod(FunctionType.MINUS)]
    public static string DOMINUS(int a, int b)
    {
        return (a - b).ToString();
    }

    [CallMethod(FunctionType.MULTIPLY)]
    public static string DOMULTIPLY(int a, int b)
    {
        return (a * b).ToString();
    }

    [CallMethod(FunctionType.DIVIDE)]
    public static string DODIVIDE(int a, int b)
    {
        return (a / b).ToString();
    }
}

属性代码:

[AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public class CallMethodAttribute : Attribute
{
    private readonly FunctionType mFunctionType;

    public CallMethodAttribute(FunctionType functionType)
    {
        mFunctionType = functionType;
    }

    public FunctionType FunctionType
    {
        get { return mFunctionType; }
    }
}

然后用反射检测给定枚举值类型对应的方法并调用它:

public class YourMagicClass
{
    private static readonly Dictionary<FunctionType, MethodInfo> FunctionTypeToMethod =
        typeof (ExecuteFunction).
            GetMethods(BindingFlags.Public | BindingFlags.Static)
                                .Where(x => x.IsDefined(typeof (CallMethodAttribute)))
                                .Select(x => new
                                    {
                                        Method = x,
                                        FunctionType = x.GetCustomAttribute<CallMethodAttribute>().FunctionType
                                    })
                                .ToDictionary(x => x.FunctionType, x => x.Method);


    public static string SomeMagicMethod(FunctionType functionType, int a, int b)
    {
        MethodInfo method;

        if (!FunctionTypeToMethod.TryGetValue(functionType, out method))
        {
            throw new ArgumentException("Could not find a handler for the given function type", "functionType");
        }
        else
        {
            string result = (string)method.Invoke(null, new object[] { a, b });

            return result;
        }
    }
}

当然,可以进行优化,例如使用 Delegate.CreateDelegate 缓存已编译的委托。

【讨论】:

  • 你是对的。我的方法是错误的。谢谢你帮助我。
【解决方案2】:

如果您准备用映射字典替换属性:

public class Function 
{
    private static readonly IDictionary<FunctionType, Func<int, int, string>> functionMappings = 
        new Dictionary<FunctionType, Func<int, int, string>>
    {
        { FunctionType.PLUS, ExecuteFunction.DOPLUS },
        { FunctionType.MINUS, ExecuteFunction.DOMINUS },
        { FunctionType.MULTIPLY, ExecuteFunction.DOMULTIPLY },
        { FunctionType.DIVIDE, ExecuteFunction.DODIVIDE },
    };

    public string Execute()
    {
        return functionMappings[_functionType]((int)Params[0], (int)Params[1]);
    }
}

【讨论】:

  • 你的回答太棒了。这可能是现在解决我的问题的替代方法。你也有我的接受。
猜你喜欢
  • 1970-01-01
  • 2019-09-13
  • 2018-02-04
  • 2016-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-06-18
相关资源
最近更新 更多