Private delegates in C #

I am working with a class that contains several variants of a private method. I am currently using an enum to select the appropriate one in cleartext.

public class MyClass
{
    public enum MyEnum { Type1, Type2, Type3, Type4 };

    private MyEnum _type;


    public MyClass(MyEnum type)
    {
        Type = type;
    }


    public MyEnum Type
    {
        get { return _type; }
        set { _type = value; }
    }


    public int Function(int x, int y)
    {
        switch(_type)
        {
            case MyEnum.Type1:
                return Function1(x,y);
            case MyEnum.Type2:
                return Function2(x,y);
            case MyEnum.Type3:
                return Function3(x, y);
            case MyEnum.Type4:
                return Function4(x, y);
        }
    }


    private int Function1(int x, int y)
    {
        // function variant 1
    }


    private int Function2(int x, int y)
    {
        // function variant 2
    }


    private int Function3(int x, int y)
    {
        // function variant 3
    }


    private int Function4(int x, int y)
    {
        // function variant 4
    }

}

      

This works great, but I'm wondering if I'm not better off with a private delegate that gets updated whenever the enum changes. Moreover, in this case the public method will be called much more often than the setter.

public class MyClass
{
    public enum MyEnum { Type1, Type2, Type3, Type4 };

    private Func<int, int, int> _function;
    private MyEnum _type;


    public MyClass(MyEnum type)
    {
        Type = type;
    }


    public MyEnum Type
    {
        get { return _type; }
        set
        {
            _type = value;
            OnTypeChange();
        }
    }


    private void OnTypeChange()
    {
        switch (_type)
        {
            case MyEnum.Type1:
                _function = Function1;
                return;
            case MyEnum.Type2:
                _function = Function2;
                return;
            case MyEnum.Type3:
                _function = Function3;
                return;
            case MyEnum.Type4:
                _function = Function4;
                return;
        }
    }


    public int Function(int x, int y)
    {
        return _function(x, y);
    }


    private int Function1(int x, int y)
    {
        // function variant 1
    }


    private int Function2(int x, int y)
    {
        // function variant 2
    }


    private int Function3(int x, int y)
    {
        // function variant 3
    }


    private int Function4(int x, int y)
    {
        // function variant 4
    }

}

      

I guess I'm just looking for some conventional wisdom on this matter. How does it usually happen in the wild?

+3


source to share


3 answers


Your second option is technically better because you don't have to go through the switch every time the public method is called.

The first is a little readable.



In all activities, however, the enumeration toggle behavior is a decent size red flag. Usually, you should subclass MyClass

and use polymorphism to get the behavior you want. I would definitely think about this in your case. In the wild, this is probably the approach I would use.

+2


source


In line with what BradleyDotNET is getting, there are ways to stick with the open / closed principle along with good design practices that harness the power of .NET. Here's a simple example of how you could implement what you are asking for, whether it is easily extensible and easily repairable.

public enum MyEnum
{
    Value1, Value2, Value3, Value4
}

[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public class MyClassHandlerAttribute : Attribute
{
    public MyEnum Handles { get; private set; }
    public MyClassHandlerAttribute(MyEnum handles) { Handles = handles; }
}

public abstract class MyClass
{
    public abstract int Function(int x, int y);
}

public static class MyClassFactory
{
    public static MyClass Create(MyEnum type)
    {
        var handler = Assembly.GetExecutingAssembly().GetTypes().Where(t =>
        {
            var a = t.GetCustomAttribute<MyClassHandlerAttribute>();
            if (a != null && a.Handles == type)
                return true;
            return false;
        }).FirstOrDefault();

        if (handler != null)
            return Activator.CreateInstance(handler) as MyClass;

        return null;
    }
}

[MyClassHandler(MyEnum.Value1)]
public sealed class MyClassType1 : MyClass
{
    public int Function(int x, int y) { return x * y; }
}

[MyClassHandler(MyEnum.Value2)]
public sealed class MyClassType2 : MyClass
{
    public int Function(int x, int y) { return x * x + y; }
}

      

You can even have subclasses have built-in default constructors, so no one outside of your assembly creates the types of any class or subclass.

If you want to step through the code, you have a type MyEnum

(which can be moved internally MyClass

, but would violate OCP if you ever had to add to it), so it is defined outside the class.



Then you have a custom attribute MyClassHandlerAttribute

so you can mark the handlers as "auto-discovered" by the factory class.

Then you have a factory that uses type checking to load handlers for your enum. Its pretty simple, it considers all assembly types with a custom attribute and if it processes that enum value, it returns it. (Someone probably has a slicker LINQ query for this, but I did it quickly)

And then you have subheadings, easily repairable, no code smell, simple short units of code.

+1


source


If you don't really want to subclass, another alternative is to use a lookup table (LUT):

    delegate int FunctionDelegate(int x, int y);

    enum FunctionName { Function1, Function2, Function3 };

    class FunctionItem
    {
        public FunctionItem(FunctionName functionName, FunctionDelegate del)
        {
            FunctionName = functionName;
            Delegate = del;
        }

        public FunctionName FunctionName
        {
            private set;
            get;
        }

        public FunctionDelegate Delegate
        {
            private set;
            get;
        }
    }

    static readonly FunctionItem[] LUT = new FunctionItem[]
    {
        new FunctionItem(FunctionName.Function1, Method1),
        new FunctionItem(FunctionName.Function2, Method2),
        new FunctionItem(FunctionName.Function3, Method3)
    };

    // Fragment of lookup:

    FunctionItem f = LUT[function];
    Debug.Assert(f.Function == function);
    int result = f.Delegate(...); // Invoke delegate

      

Not complete, but you get the idea. As an added benefit, you can extend FunctionItem

additional properties such as Name

, Description

etc. For each function.

For a suitable OO alternative, take a look at the Strategy Development Pattern (= subclass).

And this is funny because subclasses work the same ... the vtable is actually a LUT, and FunctionItem becomes an abstract base class.

0


source







All Articles