Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
203 views
in Technique[技术] by (71.8m points)

c# - Method Factory - case vs. reflection

I came across some code the other day and I wondered if that was the best way to do it. We have a method that takes a string from some web form data a does something to an object based on the string that is passed in. Currently, it uses reflection to figure which action to take, but I wondered if a switch statement would be better.

Example:

Edit: I added a third option for delegates as noted by Lucerno

public class ObjectManipulator
{
    private void DoX(object o) { }
    private void DoY(object o) { }
    private void DoZ(object o) { }

    public void DoAction(string action, object o)
    {
        switch (action)
        {
            case "DoX":
                DoX(o);
                break;
            case "DoY":
                DoY(o);
                break;
            case "DoZ":
                DoZ(o);
                break;
            default:
                throw new Exception(string.Format(
                    "Cannot locate action:{0}", action));
        }
    }

    public void DoActionViaReflection(string action, object o)
    {
        MethodInfo method = typeof(ObjectManipulator).
            GetMethod(action, new Type[] { typeof(object) });
        if (method == null)
        {
            throw new Exception(string.Format(
                "Cannot locate action:{0}", action));
        }
        else
        {
            method.Invoke(this, new object[] { o });
        }
    }
    private Dictionary<string, Action<object>> _methods;
    public ObjectManipulator()
    {
        _methods = new Dictionary<string, Action<object>>()
        {
            {"DoX", o => DoX(o)},
            {"DoY", o => DoY(o)},
            {"DoZ", o => DoZ(o)}
        };
    }
    public void DoActionViaDelegates(string action, object o)
    {
        if (!_methods.ContainsKey(action))
        {
            throw new Exception(string.Format(
                "Cannot locate action:{0}", action));
        }
        else
        {
            _methods[action](o);
        }
    }

}

The first example uses the switch and as you can see could get very verbose. The second is much shorter, but uses reflection, which I know some people avoid like the plague.

Will one method perform significantly better that the other?

Would the performance change if there were 100 different actions instead of just 3?

Which do you rather see in your code if you were reading it?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The first case will almost always be faster. However, its performance comes from the fact that it can be early bound during compile time, but that is its biggest drawback as well: this approach cannot, for instance, handle dynamically loaded assemblies, and it is much more error-prone since it is imperative and not declarative. (Forgetting a newly implemented action for instance is a thing which could happen quickly.)

My usual approach is to use reflection to implement such patterns during discovery time, but to use delegates at invocation time. This gets you the flexibility of the reflection approach with performance very close to the early-bound approach.

  • Discovery phase: use reflection to find the members (using attributes, interfaces, signatures, and/or coding conventions). In your case you always have the same signature, so the delegate to use would be Action<object>. Add those members to a Dictionary<string, Action<object>> instance, creating a delegate from the MethodInfo using CreateDelegate().

  • Invocation phase: get the delegate via its key and invoke it, which is very simple (here assuming the dictionary is called methods): methods[action](o)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...