C#中的“只读”属性访问器

时间:2009-03-06 16:16:03

标签: c# .net properties readonly accessor

我有以下课程:

class SampleClass
{
   private ArrayList mMyList;

   SampleClass()
   {
       // Initialize mMyList
   }

   public ArrayList MyList
   {
       get { return mMyList;}
   }
}

我希望用户能够获得mMyList,这就是我通过属性暴露“get”的原因,但是我不希望他们对该对象做出更改(即。MyList.Add(new Class());)回到我的班级。

我想我可以返回对象的副本,但这可能很慢,我正在寻找一种方法,它会提供编译时错误,通知用户他们不应该期望能够修改返回的该物业的价值。

这可能吗?

8 个答案:

答案 0 :(得分:25)

使用ArrayList你是相当有限的,因为BCL中没有readonly非泛型集合类。快速而肮脏的解决方案是返回一种IEnumerable。

   public IEnumerable MyList
   {
       get { return mMyList;}
   }

这实际上不会阻止某人转换为ArrayList,但默认情况下不允许编辑

您可以通过调用ArrayList.ReadOnly返回有效的只读列表。但是它的返回类型是一个ArrayList,因此用户仍然可以使用.Add编译,但它会产生运行时错误。

答案 1 :(得分:19)

使用ArrayList.ReadOnly()方法构造并返回列表周围的只读包装器。它不会复制列表,而只是围绕它创建一个只读包装器。为了获得编译时检查,您可能希望将只读包装器作为@nared建议的IEnumerable返回。

public IEnumerable MyList
{
     get { return ArrayList.ReadOnly(mMyList); }
}
  

只读的集合是   只是一个包装的集合   这会阻止修改   采集。如果对此进行了更改   底层集合,只读   集合反映了这些变化。

     

此方法是O(1)操作。

Reference

答案 2 :(得分:9)

只是为了扩展JaredPar的答案。正如他所说,返回实际的支持字段并不完全安全,因为用户仍然可以动态地将IEnumerable转换回ArrayList

我会写这样的东西,以确保不会对原始列表进行任何修改:

public IEnumerable MyList
{
    get
    {
         foreach (object o in mMyList)
             yield return o;
    }
}

然后,我可能会使用通用列表(IEnumerable<T>)完全是类型安全的。

答案 3 :(得分:4)

使用ReadOnlyCollection

  

return new ReadOnlyCollection<object>(mMyList)

您还可以将ReadOnlyCollection字段设为一个字段,它会自动反映基础列表中的更改。这是最有效的解决方案。

如果你知道mMyList只包含一种类型的对象(例如,它只有DateTimes), 您可以返回ReadOnlyCollection<DateTime>(或其他类型)以获得额外的类型安全性。如果您使用的是C#3,则只需编写

即可
  

return new ReadOnlyCollection<DateTime>(mMyList.OfType<DateTime>().ToArray())

但是,这不会自动更新基础列表,效率也会降低(它会复制整个列表)。最好的选择是使mMyList成为通用List<T>(例如,List<DateTime>

答案 4 :(得分:4)

答案 5 :(得分:1)

您应该将返回值包装在只读集合中。

答案 6 :(得分:0)

可从.NET v2.0

获取
    public ArrayList MyList { get; private set; }

答案 7 :(得分:-3)

只需将属性设置为Sealed(或VB.NET中的NotInheritable),并且只读取,如下所示:

   public sealed readonly ArrayList MyList
   {
       get { return mMyList;}
   }

另外,不要忘记将支持字段设为只读:

   private readonly ArrayList mMyList;

但是为了初始化mMyList的值,您必须仅在构造函数中初始化它,如下例所示:

public SampleClass()
{
   // Initialize mMyList
   mMyList = new ArrayList();
}