C# как защитить набор доступа, чтобы избежать установки свойства из другого класса? - PullRequest
0 голосов
/ 07 января 2020

Название может сбивать с толку, но я не нашел других слов. Лучше объяснить, что я хочу, используя образец. Представь, у меня есть 2 класса. Один из них имеет другой класс как свойство:

public class Order {
   public int?Id { get; protected set; }
   public Client Client { get; set; }

   public void Save() {
      RequestBLL bll = new RequestBLL();
      bll.Save(this);
   }

   public static Order GetBy_Id(int id) {
      RequestBLL bll = new RequestBLL();
      return bll.Get<Order>(id);
   }
}

public class Client {
   public int?Id { get; protected set; }
   public string Name { get; set; }

   public void Save() {
      RequestBLL bll = new RequestBLL();
      bll.Save(this);
   }

   public static Client GetBy_Id(int id) {
      RequestBLL bll = new RequestBLL();
      return bll.Get<Client>(id);
   }
}

Предположим, что классы находятся в сборке, отличной от приложения, и приложение имеет ссылку на сборку, в которой находятся классы. Приложение обращается к базе данных и создает объект Client. Это же приложение обращается к базе данных и создает объект Order. Этот объект Order имеет свойство Client с теми же данными, что и ранее созданный объект Client. Оба объекта Client имеют одинаковые данные, на самом деле это должен быть один и тот же объект, но это разные объекты. Приложение обновляет свойство Client.Name, используя объект Client, и сохраняет объект в базе данных. Это не отражается в клиенте внутри объекта заказа. Если объект Order будет сохранен в базе данных, предыдущее обновление будет потеряно, поскольку объект Order содержит объект Client со старыми данными:

Client c = Client.GetBy_Id(1);
Order o = Order.GetBy_Id(5);  //It has Client.Id = 1
c.Name = "Some Name";
c.Save();
o.Client.Name = "Another Name";
o.Save();

Я бы хотел избежать повторного обновления имени клиента (через объект Order) и разрешает только первое обновление напрямую, используя объект Client. Я проверил все модификаторы и не нашел никого, кого можно было бы использовать. Я попытался:

public Client Client { get; internal set; }

Но это только позволяет избежать установки свойства Client для объекта Client. Имя все еще можно установить:

c.Name = "Some Name"; //Works! It is fine.
o.Client = c; //Fails! The Client accessor does not permit this set. It is fine!
o.Client.Name = "Another Name"; //Works! And it is just what I don't want.

Я знаю, что кто-то может посоветовать не делать этого в приложении, но это не так просто. Это всего лишь простой пример, который я использовал для иллюстрации ситуации. Проблема происходит внутри фреймворка в виде циклической ссылки на несколько объектов. Приложение сохраняет только объект Order с обновленным именем клиента. Фактически это не сохранение другого объекта Client. Проблема в структуре связана с циклической ссылкой. Поэтому я пытаюсь избежать использования приложения для создания такой ситуации, заставляя Client.Name обновляться только с использованием прямого объекта Client, а не через объект Client внутри другого объекта. Есть ли способ реализовать это? Я использую свой собственный Entity Framework. Интересно, возникает ли такая же проблема в профессиональных рамках?

1 Ответ

1 голос
/ 07 января 2020

Я думаю, что лучший способ справиться с этим - использовать интерфейс (ы). Вы позволите классу Client реализовать интерфейс IClient и изменить тип возвращаемого свойства Client на IClient.

Поскольку интерфейс IClient предоставляет только метод получения, вы не можете установить свойство Name в, если только вы конвертируете / приводите значение к типу Client.

public class Order {
   public int? Id { get; protected set; }
   public IClient Client { get; set; }

   public void Save() {
      RequestBLL bll = new RequestBLL();
      bll.Save(this);
   }

   public static Order GetBy_Id(int id) {
      RequestBLL bll = new RequestBLL();
      return bll.Get<Order>(id);
   }
}

public interface IClient {
   public int? Id { get; }
   public string Name { get; }

   public void Save();
}

public class Client : IClient {
   public int? Id { get; protected set; }
   public string Name { get; set; }

   public void Save() {
      RequestBLL bll = new RequestBLL();
      bll.Save(this);
   }

   public static Client GetBy_Id(int id) {
      RequestBLL bll = new RequestBLL();
      return bll.Get<Client>(id);
   }
}

Надеюсь, это поможет Петру

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...