3

我有以下问题。

假设有一个这样定义的公共 Class1:

public class Class1
{
     public string pr1 { get; set; }
     public string pr2 { get; set; }

     public Class1()
     {
     }
}

我不允许修改类定义 - 它被其他人使用,他们需要以这种方式编写。麻烦来了。

我需要static List<Class1> myStaticList它只能在 Class2 内部修改,而其他任何地方都是真正只读的。“真正只读”是指用户不得更改任何内容,包括列表元素的属性。

像:Class2.list[0].pr1="newValue"从 Class2 外部调用的东西应该被阻止。

ReadOnlyCollection不要做任何工作,因为用户仍然可以修改列表的给定元素,因此此处给出的解决方案List<T> readonly with a private set不能满足我的需求。

基本上我已经找到了很多使列表/集合只读的可能方法(例如IReadOnlyList),但是如果它们具有公共设置器,它们都留下了更改给定列表元素属性的可能性。

我发现的唯一解决方案是创建新类:

public class Class1ReadOnly : Class1
{
    public new string pr1{ get; private set; }
    public new string pr2{ get; private set; }
    public Class1ReadOnly(Class1 tmp)
    {
        pr1= tmp.pr1;
        pr2 = tmp.pr2;
    }
}

但我希望两个能找到更好的方法,因为在我看来,仅仅因为一个只读列表就定义一个全新的类有点奇怪

提前感谢任何线索。

这甚至可能以这种不同的方式进行吗?


现实世界的上下文是这样的:

在代码中,我们编辑数据库,我想要备份已更改初始值的记录列表。我想让它保持静态只是为了有可能在我想要的任何地方恢复数据库。Class1 包含我们数据库的单个记录的所有值,因此List<Class1>我可以保留所有修改过的记录并在需要时恢复它们。而且由于它是备份,因此必须是只读的,因为意外的更改可能导致灾难。

4

3 回答 3

2

鉴于这种情况,您的方法是可行的。您正在使用适配器模式的解决方案。做这样的事情并不奇怪。

Adapter Pattern
Intent
将一个类的接口转换成客户期望的另一个接口。

- 设计模式(ISBN 0-201-63361-2)

我会定义这样一个类:

public interface IClass1 {
  string pr1 { get; }
  string pr2 { get; }
}

internal class Class1Adapter : IClass1 {
  public static Class1Adapter FromClass1(Class1 class1) {
    var pr1 = class1.pr1;
    var pr2 = class1.pr2;
    return new Class1Adapter {pr1 = pr1, pr2 = pr2};
  }

  public string pr1 { get; private set; }
  public string pr2 { get; private set; }
}

为什么要做出我所做的选择?

  • 内部类,所以我不会泄露给其他程序集。这样其他团队就无法使用Class1Adapter,除非您明确放出。
  • 实现一个新接口IClass1。您说您无法更改 的定义Class1,但如果这不是 API 的重大更改……您也许可以将其推销给其他团队。您可以使用当前的定义更改Class1来实现IClass1并且没有其他更改,您可以在您的代码中:
var list = new ReadOnlyCollection<IClass1>(source); 

// ... and later, if attempted

list[0].pr1 = "I'm breaking you!"; 

会产生:

无法将属性或索引器“ConsoleApplication19.IClass1.pr1”分配给 - 它是只读的

于 2015-04-30T07:41:39.737 回答
2

通过“我不允许更改它”,您的意思是(正如问题措辞所暗示的那样)您不允许修改类中的值?或者你真的不允许修改类声明本身?另外,如果不允许修改类声明,那么在集合中使用类的代码呢?例如,一个List<Class1>对象是否需要继续是 a ,或者你可以用其他东西List<Class1>替换类型吗?Class1


如果没有更多的上下文,很难确定什么是最适合您的情况。但是,一种可能的方法是Class1用接口替换:

interface IClass1
{
    string str1 { get; }
    string str2 { get; }
}

然后声明Class1为实现该接口,嵌套在里面Class2

class Class2
{
    private class Class1 : IClass1
    {
        public string str1 { get; set; }
        public string str2 { get; set; }
    }
}

现在,使用您已经看到的使列表本身为只读的技术,您可以防止任何其他代码替换列表中的元素(即使用接口的其他一些实现)。并且只有Class2成功地强制执行IClass1列表中的元素Class1才能获得对属性的公共 setter 的访问权限。

如果这不能解决您的问题,那么如果您可以更具体地了解解决问题的确切限制条件,将会很有帮助。

于 2015-04-30T06:07:28.303 回答
1

保护集怎么样?

https://msdn.microsoft.com/en-us/library/bcd5672a.aspx?f=255&MSPPError=-2147217396

或者您可以覆盖属性设置器。

:)

于 2015-04-30T06:09:10.663 回答