简体   繁体   English

需要像C#中的静态继承之类的东西

[英]Need something like static inheritance in C#

I'm having a small design issue and wanted to consult. 我有一个小的设计问题,想咨询。 Lets say we have the following class hierarchy: 假设我们有以下类层次结构:

abstract class A
{
}

class B : A
{
}

class C: A
{
}

I want that both B and C have a certain field x so that it's value is different between the classes but shared among all instances of the same class (ie: if b1, b2 are instances of B and c1,c2 instances of C then b1.x = b2.x and c1.x = c2.x and b1.x != c1.x). 我希望B和C都有一个特定的字段x,这样它的值在类之间是不同的,但在同一个类的所有实例之间共享(即:如果b1,b2是B和c1的实例,c的c2实例则是b1 .x = b2.x和c1.x = c2.x和b1.x!= c1.x)。 Is there an elegant way to do this by taking advantage of the fact that both B, C derive from the same base class or do I have to create a static field x in both classes? 有没有一种优雅的方法来利用B,C派生自相同的基类或我必须在两个类中创建静态字段x这一事实?

Thanks in advance. 提前致谢。

You mean like this? 你的意思是这样的?

abstract class A
{
    static Dictionary<Type, int> all_x;
    protected int X {
        get { return all_x[GetType()]; }
        set { all_x[GetType()] = value; }
    }
}

If it has to be a field so you can pass by reference: 如果它必须是一个字段,那么你可以通过引用传递:

abstract class A
{
    class SharedType { int x; }
    static Dictionary<Type, SharedType> all_shared;
    protected SharedType Shared {
        get
        {
            Type t = GetType();
            SharedType result;
            if (!all_shared.TryGetValue(t, out result) {
                 result = new SharedType();
                 all_shared.Add(t, result);
            }
            return result;
        }
    }
}

Also, we can improve performance by doing the lookup only once per instance: 此外,我们可以通过每个实例只执行一次查询来提高性能:

abstract class A
{
    class SharedType { int x; }
    static Dictionary<Type, SharedType> all_shared;
    protected SharedType Shared;
    A() {
        Type t = GetType();
        if (!all_shared.TryGetValue(t, out Shared) {
             Shared = new SharedType();
             all_shared.Add(t, Shared);
        }
    }
}

The only way I know to do this is if you make class A a generic class, ie class A<T> . 我知道这样做的唯一方法是,如果你将类A作为泛型类,即类A<T> Then have class B implement a different type for the generic type than the generic type that Class C implements. 然后让B类为泛型类型实现与C类实现的泛型类型不同的类型。

If you don't use generics, then I believe this is impossible in .NET. 如果你不使用泛型,那么我相信这在.NET中是不可能的。

Here is an example where lets say the value you were interested in was a data structure with members int Foo and string Bar. 这是一个例子,让我们说你感兴趣的值是一个数据结构,其成员是int Foo和string Bar。 One derive class could implement the an identical structure (but different derived type) than the other - the two structures would implement the same interface. 一个派生类可以实现与另一个相同的结构(但是派生类型不同) - 两个结构将实现相同的接口。

interface IAvalue
    {
        int Foo { get; set;}
        string Bar {get; set;}
    }

    struct BValue
        : IAvalue
    {

        public int Foo { get; set; }
        public string Bar { get; set; }
    }

    struct CValue
        : IAvalue
    {
        public int Foo { get; set; }
        public string Bar { get; set; }


    }

    abstract class A<T> where T : IAvalue
    {
        protected static T myValue;
    }

    class B : A<BValue>
    {
        static B()
        {
            myValue.Foo = 1;
            myValue.Bar = "text1";
        }
    }

    class C : A<CValue>
    {
        static C()
        {
            myValue.Foo = 2;
            myValue.Bar = "text2";
        }
    }

What should those values be for the field x? 这些值对于x场应该是什么? If you need to specify that the value of x for A should be "a", the value of x for B should be "b" etc., then you will have to specify the values "a", "b", ... somewhere and then you mught as well just use: 如果你需要指定A的x值应为“a”,则B的x值应为“b”等,那么你必须指定值“a”,“b”,..某处,然后你也可以使用:

abstract class A {
    public static int x = 1;    // Just using "int" as example.
}

class B : A {
    public static int x = 2;
}

If you do not care what the values are (which type do you need then) but merely want the values to be "different", then instead of using fields you could use something like: 如果您不关心值是什么(那么您需要哪种类型)但只是希望值“不同”,那么您可以使用以下内容而不是使用字段:

abstract class A {
    public int X { get { return this.GetType().GetHashCode(); } }
}

This does not take hash collisions into account, but maybe it is useful anyway? 这不会考虑哈希冲突,但也许它有用吗?

What is it you are trying to achieve? 你想要实现的目标是什么?

To build on Ben Voigt's first answer, I think what you want for your base class is this: 基于Ben Voigt的第一个答案,我认为你想要的基类是这样的:

public abstract class A
    {
        private static ConcurrentDictionary<Type, int> _typeIDs = new ConcurrentDictionary<Type, int>();
        private static int _nextID = 1;

        public int TypeID
        {
            get
            {
                return _typeIDs.GetOrAdd(this.GetType(), type => System.Threading.Interlocked.Increment(ref _nextID));
            }
        }
    }
public abstract class A
{
    public abstract int Value { get; }
}

public class B : A
{
    public override int Value { get { return 1; } }
}

public class C : A
{
    public override int Value { get { return 2; } }
}

You can use one .net feature: If you have static data members in a generic class, .net creates different instances of static data members for each generic type you use. 您可以使用一个.net功能:如果您在泛型类中有静态数据成员,.net会为您使用的每个泛型类型创建不同的静态数据成员实例。

So, you can write: 所以,你可以写:

public abstract class A<T> where T : A<T>
{
    protected static int myVariable { get; set; }
}

And inherit your classes as: 并继承您的课程:

public class B : A<B>
{
    public B()
    {
        myVariable = 1;
    }
    public int GetVariable()
    {
        return myVariable;
    }
}

public class C : A<C>
{
    public C()
    {
        myVariable = 2;
    }
    public int GetVariable()
    {
        return myVariable;
    }
}

Then every instance of B will have shared access to one instance of myVariable and every instance of C will have shared access to another. 然后, B每个实例都将拥有对myVariable一个实例的共享访问权限,并且每个C实例都将具有对另一个实例的共享访问权限。

So, if you add Set(int a) method: 所以,如果你添加Set(int a)方法:

public void Set(int a)
{
    myVariable = a;
}

And run the following code: 并运行以下代码:

static void Main(string[] args)
{
    B b1 = new B();
    C c1 = new C();
    B b2 = new B();
    C c2 = new C();

    Console.Write("{0}; ", b1.GetVariable());  // 1
    Console.Write("{0}; ", b2.GetVariable());  // 1
    Console.Write("{0}; ", c1.GetVariable());  // 2
    Console.Write("{0}; ", c2.GetVariable());  // 2

    Console.WriteLine();

    c2.Set(333);

    Console.Write("{0}; ", b1.GetVariable());  // 1
    Console.Write("{0}; ", b2.GetVariable());  // 1
    Console.Write("{0}; ", c1.GetVariable());  // 333
    Console.Write("{0}; ", c2.GetVariable());  // 333

    Console.ReadLine();
}

You get: 1; 1; 2; 2; 你得到: 1; 1; 2; 2; 1; 1; 2; 2; 1; 1; 333; 333; output. 输出。

I would suggest defining a static Dictionary<Type, Integer[]>, and having the base-class constructor call GetType() on itself and see if it's yet in the static dictionary. 我建议定义一个静态Dictionary <Type,Integer []>,并让基类构造函数自己调用GetType(),看看它是否还在静态字典中。 If not, create a new single-element array and store it in the dictionary. 如果没有,请创建一个新的单元素数组并将其存储在字典中。 Otherwise grab the array from the dictionary and store it in an instance field. 否则从字典中获取数组并将其存储在实例字段中。 Then define a property which reads or writes element zero of the array. 然后定义一个读取或写入数组元素零的属性。 This approach will achieve the requested semantics for all derivatives and sub-derivatives of the class. 该方法将实现该类的所有衍生物和子衍生物所请求的语义。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM