在父方法中访问子项的静态属性 - 设计注意事项

And*_*ter 6 .net c# class-design

我有一个类似的问题在父方法中访问子项的访问静态属性.首选答案暗示类的设计有缺陷,需要更多信息来讨论问题.

这是我想和你讨论的情况.

我想实现一些单位感知数据类型,如长度,质量,当前,......应该有一个隐式转换来从给定的字符串创建实例.例如,"1.5米"应与"150厘米"相同,或"20英寸"应正确处理.

为了能够在不同的单位之间进行转换,我需要特定数量的转换常数.我的想法是创建一个带有一些静态翻译方法的抽象基类.那些应该使用特定于类的静态字典来完成它们的工作.那么看看这个例子吧.

public class PhysicalQuantities
{
    protected static Dictionary<string, double> myConvertableUnits;

    public static double getConversionFactorToSI(String baseUnit_in)
    {
        return myConvertableUnits[baseUnit_in];
    }
}

public class Length : PhysicalQuantities
{
    protected static Dictionary<string, double> myConvertableUnits = new Dictionary<string, double>()
    {
        { "in", 0.0254 }, { "ft", 0.3048 }
    };
}

class Program
{
    static void Main(string[] args)
    {
        Length.getConversionFactorToSI("in");
    }
}
Run Code Online (Sandbox Code Playgroud)

我认为这给出了一个相当直观的用法,并使代码保持紧凑,可读性和可扩展性.但当然我遇到了引用帖子描述的相同问题.

现在我的问题是:如何通过设计避免这个问题?

Mar*_*mić 4

我认为这可以通过泛型来解决,这样看起来仍然可读。根据 Slaks 建议进行改进,将注册放入静态构造函数中,使其本身线程安全。

所以如果我没记错的话:

  • 线程安全(静态构造函数中的所有字典工作)
  • 语法仍然易于使用和可读SIConversion<Length>.GetFactor()(多 1 个字符)
  • 在派生类上实现所需的代码非常样板register(string,double);(实际上比字典定义短)

    interface ISIConversionSubscriber
    {
        void Register(Action<string, double> regitration);
    }
    
    static class SIConversion<T> where T : ISIConversionSubscriber, new()
    {
    
        private static Dictionary<string, double> myConvertableUnits = new Dictionary<string, double>();
    
        static SIConversion() {
            T subscriber = new T();
            subscriber.Register(registrationAction);
        }
    
        public static double GetFactor(string baseUnit)
        {
            return myConvertableUnits[baseUnit];
        }
    
        private static void registrationAction(string baseUnit, double value)
        {
            myConvertableUnits.Add(baseUnit, value);
        }
    
    }
    
    abstract class PhysicalQuantities : ISIConversionSubscriber
    {
        public abstract void Register(Action<string, double> register);
    }
    
    class Length : PhysicalQuantities
    {
        public override void Register(Action<string, double> register)
        {
            // for each derived type register the type specific values in this override
            register("in", 1);
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(SIConversion<Length>.GetFactor("in"));
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

输出:1

如果您想知道为什么我创建PhysicalQuantities抽象:以避免使用它,SIConversion<PhysicalQuantities>.GetFactor()因为我们没有基类的转换。无论如何,您可能不需要像这样的基类的实例 - 它不是数量的完整表示,因此它可能只包含可重用的方法。

另一个建议是使用 Enum 作为 baseUnit 而不是字符串。由于每个人都在努力实现类型安全并对魔法字符串大喊大叫,这可能是一条很好的道路:))