Нужно что-то вроде статического наследования в C # - PullRequest
3 голосов
/ 07 мая 2011

У меня небольшая проблема с дизайном, и я хотел бы проконсультироваться.Допустим, у нас есть следующая иерархия классов:

abstract class A
{
}

class B : A
{
}

class C: A
{
}

Я хочу, чтобы и B, и C имели определенное поле x, чтобы его значение отличалось между классами, но было общим для всех экземпляров одного класса (т.е.: если b1, b2 являются экземплярами B и c1, c2 являются экземплярами C, то b1.x = b2.x и c1.x = c2.x и b1.x! = c1.x).Есть ли элегантный способ сделать это, воспользовавшись тем, что оба B, C являются производными одного и того же базового класса, или мне нужно создать статическое поле x в обоих классах?

Заранее спасибо.

Ответы [ 7 ]

4 голосов
/ 07 мая 2011

Вы имеете в виду, как это?

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

Если это должно быть поле, чтобы вы могли передать по ссылке:

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

Также мы можемповысить производительность, выполняя поиск только один раз за экземпляр:

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);
        }
    }
}
0 голосов
/ 28 сентября 2011

Я бы предложил определить статический словарьи имея конструктор базового класса, вызовите GetType () для себя и посмотрите, есть ли он в статическом словаре.Если нет, создайте новый одноэлементный массив и сохраните его в словаре.В противном случае возьмите массив из словаря и сохраните его в поле экземпляра.Затем определите свойство, которое читает или записывает нулевой элемент массива.Этот подход позволит получить требуемую семантику для всех производных и субпроизводных класса.

0 голосов
/ 07 мая 2011

Вы можете использовать одну функцию .net: если у вас есть статические члены-данные в универсальном классе, .net создает различные экземпляры статических данных-членов для каждого используемого вами универсального типа.

Итак, вы можете написать:

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

И наследуйте ваши классы как:

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

Тогда каждый экземпляр B будет иметь общий доступ к одному экземпляру myVariable, а каждый экземпляр C будетимеет общий доступ к другому.

Итак, если вы добавите Set(int a) метод:

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

и выполните следующий код:

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

Вы получите: 1; 1; 2; 2; 1; 1; 333; 333; выход.

0 голосов
/ 07 мая 2011
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; } }
}
0 голосов
/ 07 мая 2011

Основываясь на первом ответе Бена Фойгта, я думаю, что вы хотите, чтобы ваш базовый класс был следующим:

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));
            }
        }
    }
0 голосов
/ 07 мая 2011

Какими должны быть эти значения для поля x? Если вам нужно указать, что значение x для A должно быть «a», значение x для B должно быть «b» и т. Д., То вам придется указать значения «a», «b», .. где-то и тогда вы должны просто использовать:

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

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

Если вам все равно, какие значения (какой тип вам нужен), а просто хотите, чтобы значения были «другими», тогда вместо использования полей вы можете использовать что-то вроде:

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

Это не учитывает коллизии хешей, но, может быть, все-таки полезно?

Чего вы пытаетесь достичь?

0 голосов
/ 07 мая 2011

Единственный способ, которым я знаю, это сделать, если вы сделаете класс A универсальным, то есть классом A<T>.Затем пусть класс B реализует другой тип для универсального типа, нежели универсальный тип, который реализует класс C.

Если вы не используете обобщенные типы, то я считаю, что это невозможно в .NET.

Вот пример, где, скажем, интересующее вас значение представляло собой структуру данных с членами int Foo и строкой Bar.Один производный класс может реализовывать идентичную структуру (но другой производный тип), чем другой - две структуры будут реализовывать один и тот же интерфейс.

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";
        }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...