Доступ к статическому свойству дочернего элемента в Родительском методе-соображения проектирования

У меня аналогичная проблема с сообщением доступ к статическому свойству ребенка в Родительском методе. Предпочтительный ответ намекает, что дизайн классов неисправен, и для обсуждения проблемы требуется дополнительная информация.

3 ответов


Я думаю, что это можно решить с помощью дженериков, чтобы все еще выглядеть читаемым. Уточненный согласно предложению Slaks, чтобы поместить регистрацию в статический конструктор, чтобы сделать его потокобезопасным как таковым.

так если я не ошибаюсь:

  • thread safe (все работы над словарем в статическом конструкторе)
  • синтаксис по-прежнему прост в использовании и читабельный 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"));
        }
    }
    

выход: 1

в случае, если вам интересно, почему я сделал PhysicalQuantities аннотация: чтобы избежать его использования с SIConversion<PhysicalQuantities>.GetFactor() поскольку у нас нет перевода базового класса. Вероятно, вам все равно не нужны экземпляры базового класса - это не полное представление количества, поэтому оно, вероятно, будет содержать только многоразовые методы.

другим предложением было бы использовать перечисление для baseUnit вместо строки. Поскольку все стремятся к безопасности типа и кричат фол на волшебных струнах, это, вероятно, хороший путь, чтобы следовать :))


лучший вариант здесь, как правило, имеет тенденцию избегать статического характера вашего дизайна и вместо этого работать с экземплярами. У меня есть аналогичная библиотека, которую я разработал, но использование имеет тенденцию быть более похожим:

static void Main()
{
    // Since I'm working with instances, I tend to pass the actual 
    // measured amount in as well...  However, you could leave this out (or pass 1)
    var len = Length.Create(42, "in"); 
    double conversionFactory = len.ConversionFactorToSI;
}

Я разработал его таким образом, чтобы я мог определить словарь для каждого типа статически, но использовать заводской метод, который передает это конструктору базового класса (который защищен). Это позволяет создать экземпляр базового класса со ссылкой на конкретный тип словарь, который работает очень аккуратно.


Я обнаружил, что test-driven-development часто приводил меня к лучшим проектам. В вашем случае "методы перевода" являются важной частью, которую вы хотите протестировать независимо от их использования в ваших классах. Я бы предложил инкапсулировать эту логику в свой собственный тип.

затем вы можете сосредоточиться на экземплярах, как предлагает Рид, зная, что ваша логика перевода хорошо проверена. Тогда ваш абстрактный базовый класс просто служит общим корнем, который знает, как получить правильный переводчик.