私有静态列表是否是限制 class 实例集的适当方法

Is a private static list an appropriate way of limiting the set of instances of a class

我试图避免使用相同的内部数据创建 class 的多个实例。我尝试了一个带有单独 class 的实现来构建 MCode,但试图保护 MCode 构造函数没有用,所以我又回到了这个实现。我想知道这是好的设计还是有什么更好的解决方案?

public class MCode : IEquatable<MCode>
{

    private readonly static List<MCode> Instances;
    public AEnum AE { get; }
    public byte C { get; }
    public BEnum BE { get; }

    public static MCode GetMCode(AEnum ae, BEnum be, byte c)
    {
            if (Instances==null)
            {
                Instances = new List<MCode>();
                var newmc = new MCode(ae, be, c);
                Instances.Add(newmc);
                return newmc;
            }

            var mc = Instances.Find(x => x.Equals(ae, be, c));

            if (mc == null)
            {
                var newmc = new MCode(ae, be, c);
                Instances.Add(newmc);
                return newmc;
            }
            return mc;
    }

    protected MCode(AEnum ae, BEnum be, byte c)
    {
        AE = ae;
        BE = be;
        C = c;
    }

    public new bool Equals(MCode mc)
    {
        return (GetHashCode() == mc.GetHashCode());
    }

    public new bool Equals(AEnum ae, BEnum be, byte c)
    {
        return (GetHashCode() == GetHashCode(ae, be, c));
    }

    public new int GetHashCode()
    {
        return ((byte)AE * 256 * 256 + (byte)BE * 256 * C);
    }

    public static int GetHashCode(AEnum ae, BEnum be, byte c)
    {
        return ((byte)ae * 256 * 256 + (byte)be * 256 * c);
    }
}

这样做的动机是我有多个包含相同 MCode 属性 的 classes 实例,我希望它们都使用相同的只读 MCode 实例。

您所描述的看起来是 Flyweight Factory pattern。享元 class 是相对较小的,并且 "unique" 对象的数量是有限的,因此维护唯一实例的目录有助于减少内存中不必要的重复数据。

一个例子是US State。只有 50 个唯一状态,因此将 50 个状态的集合作为一组唯一实例可能会在系统中有所不同,例如,每个用户记录都需要一个状态。

我也会将 class 与工厂分开。使工厂成为一个单独的 class,并为 MCode internal 创建构造函数(而不是 protected.

我也会注意您的 Equals 实施。仅仅因为两个对象具有相同的哈希码并不意味着它们是相等的。在你的情况下可能是真的,因为你有有限数量的对象可以被 int space 覆盖,但它看起来很奇怪。实施 actual Equals 逻辑(您已经在列表查找中)也将不需要重复的 GetHashCode 方法。

您可以使用工厂方法和静态字典来实现:

public class MyType
{
    private readonly static Dictionary<int, MyType> instances
       = new Dictionary<int, MyType>();

    public static MyType CreateNew(int id)
    {
        if (instances.TryGetValue(id, out var instance)
            return instance;

        return new MyType(id);
    }

    private MyType(int id) { ... }

    public int UniqueId { get; }
}

如果您的唯一标识符比 int 更复杂,我会简单地实现一个具有值相等语义的私有嵌套 struct/class 并将其用作字典的键。