Не удается определить статическое свойство абстрактной строки - PullRequest
13 голосов
/ 31 декабря 2010

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

У меня есть абстрактный класс, который содержит статический метод, который принимает статическую строку, которую я хотел бы определить как абстрактное свойство. Проблема в том, что C # не поддерживает следующее (см. Свойства ConfigurationSectionName и Current ):

    public abstract class ProviderConfiguration : ConfigurationSection
    {
        private const string _defaultProviderPropertyName = "defaultProvider";
        private const string _providersPropertyName = "providers";

        protected static string ConfigurationSectionName { get; }

        public static Configuration Current
        {
            get { return Configuration)ConfigurationManager.GetSection(ConfigurationSectionName); }
        }
    }

Полагаю, одним из способов справиться с этим было бы сделать ConfigurationSectionName НЕ абстрактным и затем создать новое определение ConfigurationSectionName в производных классах, но это выглядит довольно хакерским. Любые предложения будут приветствоваться.

Gratias !!!

Ответы [ 5 ]

11 голосов
/ 31 декабря 2010

Статические члены не имеют полиморфизма, поэтому они не могут быть абстрактными.: (

Если это то, что вам нужно, рассмотрите создание объекта Singleton и чтение свойства этого объекта.

3 голосов
/ 31 декабря 2010

Просто используйте new для переопределения статического метода в производном классе. Ничто, что делает new плохой вещью для виртуальных методов и свойств, не применимо, так как необходимо указать имя типа:

public class BaseClass
{
    public static int Max { get { return 0; } }
}

public class InteriorClass : BaseClass
{
}

public class DerivedClass : InteriorClass
{
    public new static int Max { get { return BaseClass.Max + 1; } }
}

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("BaseClass.Max = {0}", BaseClass.Max);
        Console.WriteLine("InteriorClass.Max = {0}", InteriorClass.Max);
        Console.WriteLine("DerivedClass.Max = {0}", DerivedClass.Max);
        Console.ReadKey();
    }
}
1 голос
/ 28 марта 2014

Хорошо, это не совсем для создания статического абстрактного свойства, но вы можете достичь желаемого эффекта.

Вы можете получить это, используя обобщенные значения:

public abstract class MyAbstractClass<T>
{
    public static string MyAbstractString{ get; set; }
    public static string GetMyAbstracString()
    {

        return "Who are you? " + MyAbstractString;

    }
}

public class MyDerivedClass : MyAbstractClass<MyDerivedClass>
{
    public static new string MyAbstractString
    { 
        get 
        { 
            return MyAbstractClass<MyDerivedClass>.MyAbstractString; 
        }
        set
        {
            MyAbstractClass<MyDerivedClass>.MyAbstractString = value;            
        }
    }

}


public class MyDerivedClassTwo : MyAbstractClass<MyDerivedClassTwo>
{
    public static new string MyAbstractString
    {
        get
        {
            return MyAbstractClass<MyDerivedClassTwo>.MyAbstractString;
        }
        set
        {
            MyAbstractClass<MyDerivedClassTwo>.MyAbstractString = value;
        }
    }

}


public class Test
{

    public void Test()
    {

        MyDerivedClass.MyAbstractString = "I am MyDerivedClass";
        MyDerivedClassTwo.MyAbstractString = "I am MyDerivedClassTwo";


        Debug.Print(MyDerivedClass.GetMyAbstracString());
        Debug.Print(MyDerivedClassTwo.GetMyAbstracString());


    }

}

Итак, вызовтестовый класс, который вы получите:

«Кто вы? Я MyDerivedClass» «Кто вы? Я MyDerivedClassTwo»

Итак, у вас есть статический метод в абстрактном классе, ноабстрактное значение отличается для каждого производного класса, хорошо: D

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

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

0 голосов
/ 31 марта 2018

В другом месте на этой странице @Gusman предлагает хорошее решение, дистиллированное здесь:

abstract class AbstractBase<T>
{
    public static String AbstractStaticProp { get; set; }
};

class Derived1 : AbstractBase<Derived1>
{
    public static new String AbstractStaticProp
    {
        get => AbstractBase<Derived1>.AbstractStaticProp;
        set => AbstractBase<Derived1>.AbstractStaticProp = value;
    }
};

class Derived2 : AbstractBase<Derived2>
{
    public static new String AbstractStaticProp
    {
        get => AbstractBase<Derived2>.AbstractStaticProp;
        set => AbstractBase<Derived2>.AbstractStaticProp = value;
    }
};

Однако есть несколько опасностей, на которые следует обратить внимание.

  • В основном, нет ничего, что могло бы обеспечить или требовать, чтобы какой-либо / каждый данный производный класс действительно реализовывал (psudo-) "переопределенное" статическое свойство;
  • С этим связано, поскольку не происходит унификация компилятораздесь корректные подписи (имя метода, арность параметров, типирование и т. д.) для «переопределенных» методов также не применяются.
  • Хотя универсальный параметр предназначен , чтобы быть "TSelf "производного класса, в действительности T является неограниченным и по существу произвольным.Это позволяет использовать два новых класса ошибок: если спецификация базового класса Y : AbstractBase<...> ошибочно ссылается на другой класс X, полученный из AbstractBase, значения "абстрактного статического свойства" для X и Y будут неправильно сопоставленный - и / или - любой сайт вызова AbstractBase<T>.AbstractStaticProp с аргументом ошибочного типа (таким как DateTime) самопроизвольно - и молча - потребует нового нового "экземпляра"статическое свойство.

Последняя точка маркера может быть несколько смягчена добавлением ограничения на базовую базу:

///                                v---- constraint added      
abstract class AbstractBase<TSelf> where TSelf : AbstractBase<TSelf>
{
    public static String AbstractStaticProp { get; set; }
};

Это исключает возможность class Derived2 : AbstractBase<DateTime> { /*...*/ }, но неошибка class Derived2 : AbstractBase<Derived1> { /*...*/ }.Это связано с повторяющейся загадкой, которая мешает всем попыткам ограничить универсальный тип какой-либо точной ветвью иерархии наследования типов:

"TSelf problem "
Общие ограничения всегда зависят от предоставляемых аргументов типа, что, по-видимому, влечет за собой невозможность создания общего ограничения, которое гарантирует , что некоторые конкретные TArg в пределахего область действия относится к типу, который является производным от самого себя, то есть определяемого непосредственного типа.

Ошибка в этом случае является примером этого;в то время как ограничение на AbstractBase<TSelf> исключает несовместимые непересекающиеся типы, оно не может исключать непреднамеренное использование Derived2 : AbstractBase​<Derived1>.Что касается AbstractBase, то предоставленный аргумент типа Derived1 точно удовлетворяет своему ограничению, независимо от того, какой из его подтипов получает (im-) должным образом.Я пытался все годами решать TSelf;если кто-нибудь знает трюк, который я пропустил, пожалуйста, дайте мне знать!

В любом случае, есть еще пара моментов, о которых стоит упомянуть.Например, если вы не можете немедленно обнаружить проблему в следующем коде , вы должны согласиться с тем, что это немного опасно:

public static new String AbstractStaticProp
{
    get => AbstractBase<Derived1>.AbstractStaticProp;
    set => AbstractBase<Derived2>.AbstractStaticProp = value;
}

В идеале вы хотите получить компиляторчтобы сделать то, для чего он предназначен, а именно, понять, что все экземпляры свойств AbstractStaticProp связаны между собой и, таким образом, каким-то образом обеспечить их объединение.Поскольку для статических методов это невозможно, единственная оставшаяся возможность - исключить лишние версии, эффективно сводя проблему к объединению всего лишь одной, очевидно, пустой операции.

Оказывается, исходный кодбыть слишком сложным;подход базового класса хочет, чтобы свернулся на более простом решении само по себе, без необходимости явно запрашивать его, например, эти свойства, отмеченные new, похоже, делают с квалификацией в AbstractBase<Derived1>.​AbstractStaticProp ".

Вы уже можете ссылаться на каждую соответствующую независимую копию статического свойства с помощью , квалифицируясь вместо имени производного класса (на самом деле, тестовая система @ Gusman показывает это), так что конечный результатзаключается в том, что объявления свойств в производном классе не нужны вообще. Без дальнейших церемоний, вот полная упрощенная версия:

abstract class AbstractBase<TSelf> where TSelf : AbstractBase<TSelf>
{
    public static String AbstractStaticProp { get; set; }
};

class Derived1 : AbstractBase<Derived1> { };

class Derived2 : AbstractBase<Derived2> { };

Это работает идентично коду в верхней части.те же результаты, что и раньше.

static void Test()
{
    Derived1.AbstractStaticProp = "I am Derived1";
    Derived2.AbstractStaticProp = "I am Derived2";

    Debug.Print(Derived1.AbstractStaticProp);   // --> I am Derived1
    Debug.Print(Derived2.AbstractStaticProp);   // --> I am Derived2
}
0 голосов
/ 31 декабря 2010

То, что вы пытаетесь сделать, невозможно, как уже упоминали другие.

Я бы попробовал что-то вроде этого

public abstract class ProviderConfiguration : ConfigurationSection
{
    public string ConfigurationSectionName { get; set; }

    public static ProviderConfiguration Provider { get; set; }

    public static Configuration Current
    {
        get { return (Configuration)ConfigurationManager.GetSection(Provider.ConfigurationSectionName); }
    }
}

Тогда на практике:

public void DoStuff()
{
    var provider = new DerivedProviderConfiguration();
    ProviderConfiguration.Provider = provider;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...