36

我发誓我见过这样的例子,但已经用谷歌搜索了一段时间,找不到它。

我有一个类引用了一个对象并且需要一个 GET;方法。我的问题是我不希望任何人能够摆弄它,即我希望他们获得它的只读版本,(注意我需要能够在我的班级中更改它)。

谢谢

4

7 回答 7

53

不,没有办法做到这一点。例如,如果您返回 a List<string>(并且它不是不可变的),那么调用者能够添加条目。

解决这个问题的正常方法是返回一个不可变的包装器,例如ReadOnlyCollection<T>.

对于其他可变类型,您可能需要在返回值之前对其进行克隆。

请注意,仅返回一个不可变的接口视图(例如,返回IEnumerable<T>而不是List<T>)不会阻止调用者转换回可变类型并进行变异。

编辑:请注意,除此之外,这种担忧是不可变类型更容易推理代码的原因之一:)

于 2009-06-02T13:37:09.190 回答
6

返回对精简接口的引用:

 interface IFoo
   string Bar { get; }

 class ClassWithGet
   public IFoo GetFoo(...);
于 2009-06-02T13:35:10.660 回答
4

如果对象不是太复杂/广泛,那么在它周围写一个包装器。

例如:

class A {
    public string strField = 'string';
    public int intField = 10;
}

class AWrapper {
    private A _aObj;

    public AWrapper(A aobj) {
      _aObj = A;
    }

    public string strField {
         get {
            return _aObj.strField;
         }
    }

    public int intField {
         get {
            return _aObj.intField;
         }
    }
}

所以现在你要做的就是给你的客户代码一个 AWrapper 类的实例,这样他们就可以只使用你允许他们看到的东西。

如果您的基类不是一成不变的,这可能会变得有点复杂并且可能无法很好地扩展,但对于大多数简单的情况它可能只是解决问题。我认为这被称为外观模式(但不要引用我的话=))

于 2009-06-02T14:03:28.247 回答
3

这是不可能的。获取和设置引用类型的访问器获取和设置对对象的引用。您可以通过使用私有(或内部)setter 来阻止对引用的更改,但如果对象被 getter 公开,则无法阻止对对象本身的更改。

于 2009-06-02T13:43:33.280 回答
2

您的问题看起来像您正在寻找:

public PropertyName { get; private set; }

但是,鉴于到目前为止的答案,我不确定我是否正确解释了您的问题。此外,我有什么资格去质问 Jon Skeet?:)

于 2014-01-06T23:46:30.067 回答
0

我同意 ReadOnlyCollection

看我的简单代码:

 private List<Device> _devices;
public readonly System.Collections.ObjectModel.ReadOnlyCollection<Device> Devices 
{
 get
 { 
return (_devices.AsReadOnly());
 } 

}

ReadOnlyCollection 没有 Add 方法,因此用户无法向其添加属性。但不能保证用户是否可以通过调用对象的方法来修改对象......

于 2012-06-22T13:58:33.590 回答
0

我以某种方式面对过这个问题。我有一个 CategoryViewModel 类,它有一个我想要私有只读的属性 Category :

public CategoryViewModel
{
    private Category { get; }

}

事实上,我希望它以只读方式导出到其他类。但是我不能做这样的事情。就我而言(也许它会帮助其他一些人),我想将它添加到存储库中。我发现的唯一方法是使用存储库作为参数 1 的函数,以及作为参数 2 的操作:

public void ApplyAction(ICategoryRepository repo, Action<ICategoryRepository, Category> action)
{
    action(repo, Category);
}

像那样,从其他地方,我可以做这样的事情:

 categoryViewModel.ApplyAction(_repository, (r, c) => r.MarkForInsertOrUpdate(c));

这可以帮助其他人仅在某些情况下公开那里的财产并可以管理它们。

于 2016-03-21T14:18:29.837 回答