在泛型类中使用抽象类的静态属性,该类在抽象类的子类上起作用

时间:2010-08-26 18:41:46

标签: c# generics static

我对以下代码有疑问:

abstract class a
{
    public static string x;
}



class b<c> where c : a
{
    public void f()
    {
        c.x=10;
    }
}

此代码无法编译。我在语句c.x = 10时收到错误; 。问题使得看起来条件where c:a根本没有任何影响。有人请解释为什么这是一个错误?是不是所有的孩子都将x作为静态成员共享?有没有办法解决这个问题?

我想要实现的是:我有一个a的子类,其所有对象共享一个公共属性,并且必须通过泛型类b中的f()设置此属性。如果我用a.x = 10替换有问题的陈述,这样可以吗?如果没有,a.x与c.x(或h.x,h是a的子类)有什么不同?

3 个答案:

答案 0 :(得分:8)

静态成员不是继承的,尽管通过派生类型访问静态成员是令人困惑的。例如,在以下代码中

class P
{
    public static string X;
}

class Q : P { }

class R : P { }

您可以通过P.XP.XQ.X访问R.X,但它仍然是相同的字段:

P.X = "Hello";
Q.X = "World";
Console.WriteLine(R.X);  // prints "World"

正如您所发现的,您无法使用泛型类型参数执行此操作。但是通过类型参数访问X并没有多大意义,因为您更改的是P.X,您可以直接编写而不使用泛型类型参数。


我不确定你想要实现的目标。如果您有一个抽象类A并希望从A派生的所有类型实例都具有某个属性,则可以定义:

abstract class A
{
    public abstract string X
    {
        get;
    }
}

class A1 : A
{
    public override string X
    {
        get { return "A1"; }
    }
}

class A2 : A
{
    public override string X
    {
        get { return "A2"; }
    }
}

如果要将一些信息与类型(非实例)相关联,可以使用泛型类定义一个使用类型参数化的静态字段:

class Info<T>
{
    public static string X;
}

Info<A1>.X = "Hello";
Info<A2>.X = "World";

Console.WriteLine(Info<A1>.X);  // prints "Hello"
Console.WriteLine(Info<A2>.X);  // prints "World"

这个怎么样?

abstract class Job
{
    public abstract string ExePath
    {
        get;
    }

    public void Execute(string[] args)
    {
        Console.WriteLine("Executing {0}", this.ExePath);
    }
}

abstract class Job<T> where T : Job<T>
{
    public override string ExePath
    {
        get { return JobInfo<T>.ExePath; }
    }
}

class ConcreteJob1 : Job<ConcreteJob1> { }

class ConcreteJob2 : Job<ConcreteJob1> { }

static class JobInfo<T> where T : Job<T>
{
    public static string ExePath;
}

static class JobInfoInitializer
{
    public static void InitializeExePaths()
    {
        JobInfo<ConcreteJob1>.ExePath = "calc.exe";
        JobInfo<ConcreteJob2>.ExePath = "notepad.exe";
    }
}

这与您在评论中描述的过程非常吻合。它应该工作,虽然我不是如何设计可配置的工作模型。

答案 1 :(得分:0)

如果您希望为每个子类使用不同的静态后备存储,但希望能够以多态方式从实例访问该状态,则可以执行以下操作:

abstract class A
{
    public abstract string X { get; set; }
}

class D : A
{
    private static string _x;

    public override string X
    {
        get { return _x; }
        set { _x = value; }
    }
}

A的不同子类可以提供它们自己的X实现,包括使用后备静态存储,如果需要的话。请注意,这不一定是个好主意,因为这种棘手的全局状态(伪装成实例属性)可能会使您的代码难以理解和维护。

答案 2 :(得分:0)

这是一个错误,因为cgeneric type parameter不是类型。静态成员只能通过类型访问。

  

如果我更换它,它会没用   a.x = 10时有问题的陈述?如果   不,a.x与c.x有什么不同(或者   h.x其中h是a)的子类?

您确实可以用a.x=10;替换该语句。如您所见,这意味着b.xc.xd.x也将等于10。