无法定义静态抽象字符串属性

时间:2010-12-31 01:50:24

标签: c# .net

我遇到了一个有趣的问题,我正在寻找一些关于如何最好地处理这个问题的建议......

我有一个抽象类,它包含一个静态方法,它接受一个我想要定义为抽象属性的静态字符串。问题是C#不支持以下内容(请参阅 ConfigurationSectionName 当前属性):

    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 的新定义,但这感觉非常hackish。任何建议都是最受欢迎的。

Gratias !!!

5 个答案:

答案 0 :(得分:10)

静态成员没有多态性,因此它们不能是抽象的。 :(

如果这就是您所需要的,请考虑制作一个Singleton对象,并从该对象中读取该属性。

答案 1 :(得分:3)

只需使用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();
    }
}

答案 2 :(得分:1)

好的,这不是创建一个静态抽象属性,但是你可以达到预期的效果。

你可以通过使用泛型来获得这个:

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());


    }

}

所以,调用测试类,你会得到:

&#34;你是谁?我是MyDerivedClass&#34; &#34;你是谁?我是MyDerivedClassTwo&#34;

所以,你在抽象类中有一个静态方法,但每个派生类的抽象值都不同,很好:D

好的,那么,到底是怎么回事?技巧是泛型标记,编译器 为每个派生类型生成不同的抽象类

正如我所说,它不是一个抽象属性,但你可以获得抽象静态属性的所有好处,它们在抽象类上编写静态函数,但每种类型使用不同的静态参数。

答案 3 :(得分:0)

正如其他人所提到的那样,你想要做的事是不可能的。

我会尝试这样的事情

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

答案 4 :(得分:0)

在本页的其他地方,@ Gusman proposes这里提炼出了很好的解决方案:

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-)“重写”静态属性;
  • 与此相关,由于此处没有编译器统一,因此也不会强制执行“覆盖”方法的正确签名(方法名称,参数arity,类型等)。
  • 虽然泛型参数意图是派生类的“TSelf”,但实际上T不受约束且基本上是任意的。这会导致两类新的错误:如果基类规范Y : AbstractBase<...>错误地引用了不同的AbstractBase派生类X,那么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 问题”
  通用约束总是受所提供的类型参数的支配,这似乎意味着不可能构造一个通用约束保证其范围内的某些特定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 - 标记的属性似乎在{{ {1}}“。

您已经可以通过使用派生类名称来确定静态属性的每个相应独立副本而不是(实际上,@ Gusman的测试工具显示了这一点),因此最终结果是派生类中的属性声明根本不是必需的。不用多说,这是完整的简化版本:

AbstractBase<Derived1>.​AbstractStaticProp

这与顶部的代码完全相同。测试工具提供与以前相同的结果。

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

class Derived1 : AbstractBase<Derived1> { };

class Derived2 : AbstractBase<Derived2> { };