2

我有一个业务实体如下,

class Class1
{
   List<Class2> classes = new List<Class2>();

   public IEnumerable<Class2> Classes { get { return classes.AsEnumrable(); }

   public void AddClass(Class2 cls)
   {
       classes.Add(cls);
   }
}

class Class2
{
    public string Property { get; set; }
}

我的业务逻辑要求,一旦Class2使用该方法将实例添加到列表AddClass顶部,任何人都不应编辑先前添加到列表中的实例的属性,只能编辑列表中的最后一项。我该怎么做呢?ClassesClass1Class2

我已经尝试过 IReadOnlyList,但它似乎与使列表结构本身不可编辑而不会阻止对其项目内容的编辑有关。

4

4 回答 4

2

决定其项目的行为不是容器的工作。容器就是这样 - 一个包含其他对象的对象。AnIReadOnlyList是一个容器,其项目不能被修改。但是其中的项目是 jsutClass2实例 - 容器无法阻止它们被编辑。

考虑一下:

myReadOnlyCollection[0].Property = "blah";
var firstItem = myReadOnlyCollection[0];
firstItem.Property = "blah";

在您的情况下这应该是合法的吗?两者有什么区别?firstItem只是一个Class2不知道它曾经在只读集合中的实例。

你需要的是Class2它本身是不可变的。这取决于类,而不是容器。阅读不变性,这是一个需要掌握并相应实施的重要概念Class2。如果你需要一个常规的、可变Class2的来改变它的行为,也许可以添加一个ToImmutable()方法来返回一个不同的项目,而不需要一个 setter。

于 2018-02-11T15:28:43.697 回答
2

你为什么要曝光IReadOnlyCollection。一旦你暴露了对象,对象本身就必须是不可变的。

为什么不只公开您要公开的唯一对象?

   private IEnumerable<Class2> Classes { get { return classes; }

   public Class2 Class2Instance { get { return classes.Last(); } }
于 2018-02-11T15:32:50.090 回答
1

我只能看到三个选项。一种是更改 Class2 以使其可锁定,然后在将其添加到您的列表后将其锁定...

class Class1 {
   List<Class2> classes = new List<Class2>();

   public IEnumerable<Class2> Classes {
      get { return classes.AsEnumrable();
   }

   public void AddClass(Class2 cls) {
      cls.Lock();
      classes.Add(cls);
   }
}

class Class2 {
    private string _property;
    private bool _locked;

    public string Property {
       get { return _property; }
       set {
          if(_locked) throw new AccessViolationException();
          _property = value;
       }
    }

    public void Lock() {
       _locked = true;
    }
}

另一种选择是只返回列表对象的值而不是对象本身......

class Class1 {
   List<Class2> classes = new List<Class2>();

   public IEnumerable<string> Values {
      get { return classes.Select(cls => cls.Property); }
   }

   public void AddClass(Class2 cls) {
      classes.Add(cls);
   }
}

在第二种方法中,除了单个值之外的任何内容,您都需要返回一个元组。或者,您可以为 Class2 创建一个特定容器,将值公开为只读...

class Class2ReadOnly {
   private Class2 _master;

   public Class2ReadOnly(Class2 master) {
      _master = master;
   }

   public string Property {
      get { return _master.Property; }
   }
}

class Class1 {
   List<Class2ReadOnly> classes = new List<Class2ReadOnly>();

   public IEnumerable<Class2ReadOnly> Classes {
      get { return classes.AsEnumerable(); }
   }

   public void AddClass(Class2 cls) {
      classes.Add(new Class2ReadOnly(cls));
   }
}
于 2018-02-11T16:04:03.793 回答
0

正如其他人所说,决定您是否(以及如何)访问它的元素并不是集合的工作。我确实看到了解决方法:

例外和参考:

修改 Class2,使其可以引用 Class1。如果设置了引用,则在所有设置器上抛出异常。修改 Class1.AddClass 以设置该属性。

一个更软的版本将是 Class2 上的“只读”属性,所有其他代码都必须检查。

只读属性和构造函数:

总是给 Class2 只读属性(私有集)。如果要定义属性值,则必须在构造函数(具有适当的参数)中执行此操作。这种模式被 Exception 类大量使用。

传承诡计:

在继承链中创建多个 Class2 版本,以便可以将 Class2Writebale 强制转换为 Class2ReadOnly。

接受错误的 Y:

您可能陷入了 XY 问题:https ://meta.stackexchange.com/questions/66377/what-is-the-xy-problem 如果是这样,请退后一步修复它。

于 2018-02-11T15:44:29.853 回答