19

我有以下课程:

class SampleClass
{
   private ArrayList mMyList;

   SampleClass()
   {
       // Initialize mMyList
   }

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

我希望用户能够获取 mMyList 这就是为什么我通过属性公开“get”但是我不希望他们对对象(即 MyList.Add(new Class());) 进行更改以使其回到我的课堂。

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

这可能吗?

4

8 回答 8

25

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

   public IEnumerable MyList
   {
       get { return mMyList;}
   }

这实际上不会阻止某人投射到 ArrayList 但默认情况下也不允许编辑

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

于 2009-03-06T16:17:40.167 回答
19

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

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

只读集合只是一个带有防止修改集合的包装器的集合。如果对基础集合进行了更改,则只读集合会反映这些更改。

此方法是 O(1) 操作。

参考

于 2009-03-06T16:18:51.477 回答
9

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

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

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

再说一次,我可能还会使用通用列表 ( IEnumerable<T>) 来保证类型安全。

于 2009-03-06T17:18:25.217 回答
4

使用ReadOnlyCollection.

return new ReadOnlyCollection<object>(mMyList).

您也可以创建ReadOnlyCollectiona 字段,它会自动反映基础列表中的更改。这是最有效的解决方案。

如果您知道 mMyList 仅包含一种类型的对象(例如,它除了 DateTimes 之外什么都没有),您可以返回一个ReadOnlyCollection<DateTime>(或一些其他类型)以获得额外的类型安全性。如果您使用的是 C# 3,您可以简单地编写

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

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

于 2009-03-06T17:50:02.583 回答
4

List(T).AsReadOnly 方法=)

于 2009-03-06T17:54:46.207 回答
1

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

于 2009-03-06T16:17:45.987 回答
0

可从 .NET v2.0 获得

    public ArrayList MyList { get; private set; }
于 2013-03-25T20:50:05.323 回答
-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();
}
于 2009-03-06T16:42:44.507 回答