1

First, I'm so sorry because my bellow stupid question. But I hope someone can help me on this approach.

I have an Enum that I want to be add new magic attribute as described:

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
    }

My class has a FunctionType property like this:

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
        }
    }

Last, my calculate class has some functions return result:

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();
        }
    }

My stupid question is: How can I implement CallMethodAttribute in enum and SomeMagicMethod above to run specified method without using switch case as normal ?

1
  • Forget the calling part for the moment - your attribute simply isn't going to be compilable right now, as the argument for the attribute has to be a compile-time constant value of one of a few supported types. You could have a string specifying the name of the method though. As an aside, I would strongly suggest following .NET naming conventions - lose the shouty names. Commented Aug 15, 2014 at 8:32

2 Answers 2

4

You can't put a reference to a method in an attribute as you wrote (it is not compile-time).

Your approach is wrong - You should decorate the methods with an attribute referring their corresponding enum, like this:

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();
    }
}

The attribute code:

[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; }
    }
}

And then detect the corresponding method for a given enum value type with reflection and invoke it:

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;
        }
    }
}

Of course, optimizations can be done such as caching a compiled delegate using Delegate.CreateDelegate.

Sign up to request clarification or add additional context in comments.

1 Comment

You're right. I was wrong in my approach. Thanks you for helping me.
2

If you're ready to replace your attributes with a mapping dictionary:

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]);
    }
}

1 Comment

Your answer is so great. It's maybe alternative way to solve my problem now. You also have my accepted.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.