как защитить стати c int в C# - PullRequest
2 голосов
/ 19 марта 2020

Я учусь C#, поэтому я все еще нахожусь здесь по основам. Это мой код

class foo
{
  protected int id;
  protected string data;
  static int nextId = 1;

  public int Id
  {
    get { return id; }
  }

  public foo()
  {
    this.id = nextId++;
  }
  public foo(string somedata)
  {
    this.data = somedata;
    this.id = nextId++;
  }
}

Этот код пока работает отлично. Все объекты будут иметь уникальный идентификатор с ними.

Проблема в том, что я не хочу, чтобы первый идентификатор был 1, я хочу, чтобы это был номер в первой строке файла, заданный в качестве аргумента для приложения из командной строки. Если файл не указан или файл не существует, то он может быть одним. Есть ли способ сделать одноразовый метод для установки nextId, чтобы он не мог быть изменен вне класса после того, как он был когда-то установлен?

Дух ... Я думаю это это трюк Тем не менее, я хотел бы знать, есть ли какая-то сборка для создания переменных, которые можно установить только один раз.

public int nextId
{
  set {if(nextId<1) nextId = value;}
}

Ответы [ 3 ]

2 голосов
/ 19 марта 2020

Вы можете реализовать stati c конструктор , который присваивает правильное значение nextId перед первым использованием foo класса:

using System.IO;
using System.Linq; 
...

class foo
{
  ...
  static int nextId;

  // read-only property which however can be assigned in the constructor
  public int Id {get;}

  // This static costructor will be called once before 1st usage of foo class
  static foo() {
    //TODO: put the right file name here
    string fileName = Environment.GetCommandLineArgs()[1];

    nextId = int.Parse(File 
      .ReadLines(fileName)
      .First());  
  }

  public foo()
  {
    //Let's increment nextId in thread-safe manner
    Id = Interlocked.Increment(ref nextId);
  }

  ...
}
1 голос
/ 19 марта 2020

В качестве альтернативы ответа Дмитрия , вы можете определить инициализацию с помощью метода stati c. Я предпочитаю избегать использования stati c конструкторов, если несколько полей не нужно инициализировать одновременно.

using System.IO;
using System.Linq; 
...

class foo
{
  ...
  // The initialization will be called at some time before first use of nextId.
  private static int nextId = GenerateInitialNextId();

  // read-only property which however can be assigned in the constructor
  public int Id {get;}

  private static int GenerateInitialNextId() {
    //TODO: put the right file name here
    string fileName = Environment.GetCommandLineArgs()[1];

    return int.Parse(File 
      .ReadLines(fileName)
      .First());  
  }

  public foo()
  {
    //Let's increment nextId is thread-safe manner
    Id = Interlocked.Increment(ref nextId);
  }

  ...
}
1 голос
/ 19 марта 2020

Вы можете сделать это

class foo
{
  private static int nextId = 1;
  private static bool isNextIdSet;

  public SetId(newId)
  {
    if (!isNextIdSet) nextId = newId;
    isNextIdSet = true;
  }
}

Таким образом, nextId может быть установлен только один раз за пределами класса.

ОБНОВЛЕНИЕ: если вы предпочитаете использовать это со многими переменными, вы можете создать помощник для этого, например

class SetOnlyOnce<T>
{
  private bool isSet;
  public T Value
  { 
    get;
    set
    {
      if (!isSet) Value = value;
      isSet = true;
    }
  }
}

Затем используйте его как

class Foo
{
  public SetOnlyOnce<int> prop1 {get;set;}
  public SetOnlyOnce<string> prop2 {get;set;}
}

class Bar
{
  public Bar()
  {
    var foo = new Foo();
    foo.prop1.Value = 2;
    foo.prop1.Value = 3; // this doesn't set.
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...