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?
source to share
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.
source to share
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.
source to share
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.
source to share