C# 中的私有委托

Private delegates in C#

我正在使用一个 class,其中包含私有方法的多个变体。目前,我正在使用枚举 select 公开方法中的适当枚举。

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
    }

}

这很好用,但我想知道我是否最好使用一个私有委托,它会在枚举更改时更新。特别是因为在这种情况下,public 方法将比枚举 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
    }

}

我想我只是在寻找关于这个主题的一些传统智慧。这种事情在野外通常是如何处理的?

你的第二个选择技术上更好,因为你不必在每次调用 public 方法时都进行切换。

第一个更具可读性。

尽管如此,在所有现实中,枚举的切换行为是一个相当大的危险信号。通常您会子类化 MyClass 并使用多态性来获得所需的行为。对于您的情况,我肯定会考虑这样做。 "In the wild",这可能是我会使用的方法。

按照 BradleyDotNET 的目标,有一些方法可以遵循 open/closed 原则以及利用 .NET 强大功能的良好设计实践。这是一个简单的示例,说明如何实现您的要求,使其易于扩展且易于维护。

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

您甚至可以让 subclasses 具有内部默认构造函数,这样程序集之外的任何人都不会创建任何 class 或 subclass 的类型。

如果您想浏览代码,可以使用 MyEnum 类型(可以将其移到 MyClass 中,但如果您必须向其中添加,则会违反 OCP ), 所以它定义在 class.

之外

然后您有一个自定义属性 MyClassHandlerAttribute,因此您可以将处理程序标记为 "auto-discovered" 由工厂 class。

然后你就有了工厂,它使用类型检查来为你的枚举加载处理程序。它非常简单,它使用自定义属性查看程序集中的所有类型,如果它处理该枚举值,它 returns 它。 (有人可能对此有更巧妙的 LINQ 查询,但我很快就做到了)

然后你有你的子 classes,易于维护,没有代码味道,简单的短代码单元。

如果你真的不想subclass,另一种方法是使用查找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

不完整,但你明白了。作为一个额外的优势,您可以为 FunctionItem 扩展每个函数的额外属性,例如 NameDescription 等。

至于合适的 OO 替代方案,请查看 Strategy 设计模式 (= subclassing)。

这很有趣,因为 subclassing 的工作原理是一样的...vtable 实际上是一个 LUT,而 FunctionItem 变成了一个抽象基础 class.