使收集项目只读

时间:2018-02-11 15:18:43

标签: c# readonly-collection

我有以下商业实体,

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实例添加到ClassesClass1列表的顶部后,任何人都无法编辑先前添加到列表中的Class2个实例的属性,只能编辑列表中的最后一个项目。我该怎么做?

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

4 个答案:

答案 0 :(得分:2)

决定其项目行为并不是容器的工作。容器就是那个 - 包含其他对象的对象。 IReadOnlyList是一个无法修改其项目的容器。但其中的项目是jsut Class2个实例 - 容器无法阻止它们被编辑。

考虑一下:

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

这在您的方案中是否合法?这两者之间的区别是什么? firstItem只是Class2的一个实例,它不知道它曾经只是一个只读集合。

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

答案 1 :(得分:2)

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

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

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

   public Class2 Class2Instance { get { return classes.Last(); } }

答案 2 :(得分:1)

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

from sys import stdin

def main():
    curr_line=stdin.readline()
    while curr_line!=None:
        x = []
        curr_line = curr_line.split()
        num1 = int(curr_line[0])
        num2 = int(curr_line[1])
        index = 0
        for i in range(num1, num2+1):
            counter = 1
            while i != 1:
                if i % 2  == 1:
                    i = 3*i + 1
                else:
                    i = i/2
                counter += 1
            x.append(counter)
            index += 1            
        print(num1, num2, max(x), sep = " ")
        curr_line=stdin.readline()
    return 
main()

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

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

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

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

答案 3 :(得分:0)

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

例外&amp;参考文献:

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

更柔和的版本是&#34;只读&#34; Class2上的属性,所有其他代码都必须检查。

Readonly Properties&amp;构造函数:

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

继承Shenanigans:

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

接受错误的Y:

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