代码之家  ›  专栏  ›  技术社区  ›  Aadith Ramia

在处理抽象类的子类的泛型类中使用抽象类的静态属性

  •  0
  • Aadith Ramia  · 技术社区  · 15 年前

    我有一个关于以下代码的问题:

    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的所有子代共享为静态成员,这不是真的吗?有没有办法规避这个问题?

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

    3 回复  |  直到 15 年前
        1
  •  8
  •   dtb    15 年前

    静态成员不会被继承,尽管通过派生类型访问静态成员的可能性令人困惑。例如,在下面的代码中

    class P
    {
        public static string X;
    }
    
    class Q : P { }
    
    class R : P { }
    

    您可以访问 P.X 通过 P.X Q.X R.X 但它仍然是同一个领域:

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

    正如您所发现的,不能使用泛型类型参数来执行此操作。但访问 X 虽然类型参数并不是很有意义,因为你所改变的只是 P.X 不使用泛型类型参数直接编写。


    我不太确定你想达到什么目的。如果你有一个抽象类 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";
        }
    }
    

    这与您在评论中描述的过程非常吻合。它应该可以工作,尽管我不会设计一个可配置的工作模型。

        2
  •  0
  •   Dan Bryant    15 年前

    如果您希望为每个子类使用不同的静态备份存储,但希望能够以多态方式从实例访问状态,可以这样做:

    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实现,包括使用支持静态存储。注意,这不一定是一个好主意,因为这种复杂的全局状态(假装为实例属性)可能会使代码难以理解和维护。

        3
  •  0
  •   Jeff Sternal    15 年前

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

    我可以换一下吗 有疑问的陈述,a.x=10?如果 不是,a.x和c.x有什么不同(或 H.X,其中H是A的子类?

    您确实可以用 a.x=10; . 正如你所观察到的,这意味着 b.x , c.x d.x 也等于10。