Как создать статическую переменную, совместно используемую экземплярами закрытых построенных универсальных типов? - PullRequest
0 голосов
/ 30 сентября 2019

Я хочу иметь этот универсальный класс:

public class MyClass<T>
{
  static public string SharedString;
}

Где SharedString будет статическим значением, которое будет иметь одинаковое значение для всех экземпляров закрытых построенных типов.

Следовательно, эти случаи:

var instanceInt = new MyClass<int>();
var instanceString = new MyClass<string>();

Будет иметь то же значение для поля SharedString.

Например, если я напишу:

instanceInt.SharedString = "Text 1";
instanceString.SharedString = "Text 2";

Тогда яхотите, чтобы instanceInt.SharedString == "Text 2".

В C # SharedString имели одинаковое значение для всех экземпляров MyClass<int>, но оно отличается от SharedString экземпляров MyClass<string>.

Итак, instanceInt.SharedString == "Text 1".

Я хочу иметь возможность повторно использовать эту концепцию для создания любого класса с любым истинным универсальным статическим полем , которое может быть public, а также private или internal.

Я прочитал это, но это неадекватно, так как я не хочу повторять код каждый раз, когда мне нужно общее значение:
Совместное использование статических полей среди различных экземпляров универсального класса

Я не хочу создавать базовый класс для каждого универсального типа, ни для вложенных, ни для классов-оболочек: это слишком трудоемко, тяжелои не факторизован. Я просто хочу иметь возможность определить несколько общих открытых типов и добавить в них некоторые общие статические переменные.

Как устранить этот недостаток универсального полиморфизма?

Ответы [ 2 ]

2 голосов
/ 30 сентября 2019

Есть 3 способа, которые, я думаю, будут работать для вас:

  1. Создать неуниверсальный базовый класс, содержащий общие поля
  2. Создать неуниверсальный отдельный класс, содержащий общие поля
  3. Создайте неуниверсальный тип, который содержит эти общие значения, и повторно используйте его внутри ваших общих

Для третьего, так как вы говорите, что вы на самом деле не хотите вариант 1 или 2, вот пример:

public abstract class Shared
{
    private readonly static Dictionary<Guid, object> _Variables
        = new Dictionary<Guid, object>();

    protected void SetValue<T>(Guid key, T value)
    {
        lock (_Variables)
            _Variables[key] = value;
    }

    protected T GetValue<T>(Guid key)
    {
        object temp;
        lock (_Variables)
            if (!_Variables.TryGetValue(key, out temp))
                return default;

        return (T)temp;
    }
}

public class Shared<T> : Shared
{
    private readonly Guid _Key;

    public Shared(Guid key)
    {
        _Key = key;
    }

    public T Value
    {
        get => GetValue<T>(_Key);
        set => SetValue<T>(_Key, value);
    }
}

Вы могли бы использовать это так:

public class MyClass<T>
{
    private static readonly Shared<string> _Shared
        = new Shared<string>(Guid.Parse("521ecaba-2a5e-43f2-90e0-fda38a32618c"));

    public void Set(string value)
    {
        _Shared.Value = value;
    }

    public void Get()
    {
        Console.WriteLine(_Shared.Value);
    }
}

НаборМетоды / Get этого MyClass использовались для проверки того, что значение, установленное через один закрытый тип, доступно через другой, например:

var mc1 = new MyClass<int>();
var mc2 = new MyClass<string>();

mc1.Set("Test");
mc2.Get();

Это выдаст Test.

Даже есливсе закрытые типы MyClass<T> будут иметь свой собственный статический экземпляр Shared<T>, значение , содержащееся в этом экземпляре, будет поддерживаться общим словарем, который совместно используется всеми типами, использующими этот тип Shared<T>.


Лично я бы порекомендовал пойти сстатический неуниверсальный базовый класс, хотя:

public abstract class MyClass
{
    protected static string _Shared;
}

public class MyClass<T> : MyClass
{
    public void Set(string value)
    {
        _Shared = value;
    }

    public void Get()
    {
        Console.WriteLine(_Shared);
    }
}

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

internal static class MyClassShared
{
    public static string Shared;
}

public class MyClass<T>
{
    public void Set(string value)
    {
        MyClassShared.Shared = value;
    }

    public void Get()
    {
        Console.WriteLine(MyClassShared.Shared);
    }
}
0 голосов
/ 30 сентября 2019

Вот мое решение, полученное из решения @ LasseVågsætherKarlsen

Использование идеи Guid и Dictionary.

Наконец-то это работает, и это так же просто, как просто!

Я полагаю, что преимущество факторизации и возможности повторного использования его решения перевешивает другие повторяющиеся коды и снижает производительность.

Код теперь может быть уменьшен и более удобен в обслуживании.

Спасибо.

Класс SharedStaticValue

public class SharedStaticValue<T>
{

  static private class Collector
  {
    static private readonly object locker = new object();
    static private readonly Dictionary<Guid, object> _Values
        = new Dictionary<Guid, object>();
    static internal void SetValue<T>(Guid key, T value)
    {
      lock ( locker )
        if ( _Values.ContainsKey(key) )
          _Values[key] = value;
        else
          _Values.Add(key, value);
    }
    static internal T GetValue<T>(Guid key)
    {
      lock ( locker )
        if ( _Values.ContainsKey(key) )
          return (T)_Values[key];
        else
        {
          T value = default(T);
          _Values.Add(key, value);
          return value;
        }
    }
  }

  private readonly Guid ID;

  public T Value
  {
    get { return Collector.GetValue<T>(ID); }
    set { Collector.SetValue(ID, value); }
  }

  public override string ToString()
  {
    return Value.ToString();
  }

  public SharedStaticValue(Guid id)
  {
    ID = id;
  }

}

Тест

public class GenericClass<T>
{
  static public int Value
  {
    get { return _Value.Value; }
    set { _Value.Value = value; }
  }
  static private SharedStaticValue<int> _Value
    = new SharedStaticValue<int>(Guid.Parse("521ecaba-2a5e-43f2-90e0-fda38a32618c"));
}

internal class Class1 : GenericClass<int>
{
}

internal class Class2 : GenericClass<string>
{
}

internal class SharedStaticValueTest
{
  private SharedStaticValue<int> value 
    = new SharedStaticValue<int>(Guid.Parse("{E838689A-3B2C-4BFB-A15C-2F1B5D65F1DE}"));
  public void RunTest()
  {
    Action<string> write = (str) =>
    {
      Console.WriteLine(str);
      Console.WriteLine("  this.SharedStaticValue<int> = " + value.Value);
      Console.WriteLine("  GenericClass<double> = " + GenericClass<double>.Value);
      Console.WriteLine("  GenericClass<int> = " + GenericClass<int>.Value);
      Console.WriteLine("  Class1 extend GenericClass<int> = " + Class1.Value);
      Console.WriteLine("  Class2 extend GenericClass<string> = " + Class2.Value);
      Console.WriteLine();
    };
    write("Default values");
    value.Value = 10;
    write("Set this.SharedStaticValue<int>.Value = 10");
    GenericClass<double>.Value = 20;
    write("Set GenericClass<double>.Value = 20");
    GenericClass<int>.Value = 30;
    write("Set GenericClass<int>.Value = 30");
    Class1.Value = 40;
    write("Set Class1 extend GenericClass<int>.Value = 40");
    Class2.Value = 50;
    write("Set Class2 extend GenericClass<string>.Value = 50");
  }
}

Выход

Default values
  this.SharedStaticValue<int> = 0
  GenericClass<double> = 0
  GenericClass<int> = 0
  Class1 extend GenericClass<int> = 0
  Class2 extend GenericClass<string> = 0

Set this.SharedStaticValue<int>.Value = 10
  this.SharedStaticValue<int> = 10
  GenericClass<double> = 0
  GenericClass<int> = 0
  Class1 extend GenericClass<int> = 0
  Class2 extend GenericClass<string> = 0

Set GenericClass<double>.Value = 20
  this.SharedStaticValue<int> = 10
  GenericClass<double> = 20
  GenericClass<int> = 20
  Class1 extend GenericClass<int> = 20
  Class2 extend GenericClass<string> = 20

Set GenericClass<int>.Value = 30
  this.SharedStaticValue<int> = 10
  GenericClass<double> = 30
  GenericClass<int> = 30
  Class1 extend GenericClass<int> = 30
  Class2 extend GenericClass<string> = 30

Set Class1 extend GenericClass<int>.Value = 40
  this.SharedStaticValue<int> = 10
  GenericClass<double> = 40
  GenericClass<int> = 40
  Class1 extend GenericClass<int> = 40
  Class2 extend GenericClass<string> = 40

Set Class2 extend GenericClass<string>.Value = 50
  this.SharedStaticValue<int> = 10
  GenericClass<double> = 50
  GenericClass<int> = 50
  Class1 extend GenericClass<int> = 50
  Class2 extend GenericClass<string> = 50
...