【问题标题】:Weird VB.NET array-property situation奇怪的 VB.NET 数组属性情况
【发布时间】:2010-12-30 06:26:00
【问题描述】:

我遇到了这种奇怪的情况。

我有这两个类:

Public Class Entry

End Class

Public Class Core

End Class

Core 类的属性之一是一个 Entry 对象数组。如何申报?

现在,从外部更改(添加/删除)此数组的唯一方法应该是使用两个函数 - AddEntry(Ent As Entry) 和 RemoveEntry(ID As String)。请注意,在这里,调用 AddEntry 函数的人应该只关心创建一个 Entry 对象并传递它。它将被添加到现有数组中。

但是,Entry 数组应该可以像这样从外部访问,用于循环和打印或类似这样:

' core1 is a valid Core object
For Each Ent As Entry In core1.Entries
  MsgBox(Ent.SomeProperty)
Next Ent

是否可以将数组公开为属性,但仅通过函数限制修改?我知道 Add 和 Remove 函数中的逻辑可以在 setter 或 getter 中,但是想要添加的人应该只传递一个 Entry 对象。

这就像说您对数组具有只读访问权限,但要修改它,只需创建一个对象并发送它或发送 ID 以将其删除。不用担心整个数组。

我希望我说得通。

【问题讨论】:

    标签: vb.net arrays class properties


    【解决方案1】:

    为什么要将它公开为数组?

    我会做的是在内部使用 List 来存储条目。 (该列表将是私有的) 创建必要的公共方法(AddEntry / RemoveEntry / ... ),用于操作私有列表。

    然后,创建一个公开列表的公共属性,但以只读方式。也就是说,该属性应该返回一个 ReadOnlyCollection 实例。 像这样:

    (我知道它是用 C# 编写的,但那是我的“主要语言”——有点懒得把它转换成 VB.NET)

    public class Core
    {
        private List<Entry> _entries = new List<Entry>();
    
        public void AddEntry( Entry entry )
        {
            _entries.Add (entry);
        }
    
        public ReadOnlyCollection<Entry> Entries
        {
           get { return _entries.AsReadOnly(); }
        }
    }
    

    编辑:MarkJ提供的VB.Net版本

    Imports System.Collections.ObjectModel 
    Public Class Core 
      Private _entries As New List(Of Entry) 
    
      Public Sub AddEntry( new As Entry ) 
        _entries.Add (new) 
      End Sub 
    
      Public ReadOnly Property Entries() As ReadOnlyCollection(Of Entry) 
        Get 
          Return _entries.AsReadOnly 
        End Get 
      End Property 
    End Class 
    

    【讨论】:

    • +1 嘿,没有问题,我会弄清楚如何转换为 VB :) 感谢您的代码。我会看看我能不能让它工作。
    • 普通数组能否以只读方式返回?将条目()调暗为条目。条目可以作为只读返回吗?或者我应该只对 List、ArrayList 或此类对象执行此操作?
    • 但是,您是否真的想在内部使用数组?我认为这只会让事情变得更复杂。也许您可以通过在其构造函数中传递数组来创建 ReadOnlyCollection 实例。如果没有,那么您可以通过将数组传递给 List 的构造函数来创建一个 List,然后在列表上调用 'AsReadOnly',以获取 ReadOnlyCollection 实例。
    • 没有真正的原因。只是好奇 :D 所以这不可能吗?
    • 另外,如果我有一个列表并像你在 getter 方法中一样返回,我可以使用 ForEach 循环吗?
    【解决方案2】:

    为数组创建一个私有字段,然后创建访问方法以在内部使用数组。为了将此数组公开给调用者以便他们可以枚举它,您应该公开IEnumerable(Of T) 类型的属性。

    这种方法并非万无一失,但是聪明的调用者可以简单地将IEnumerable(Of T) 转换回数组并对其进行修改,因此可能需要创建数组的副本并返回那个作为IEnumerable(Of T)。正如我相信您已经看到的那样,所有这些都会带来明显的性能损失。这只是将数组用作底层数据结构时可能出现的众多问题之一。

    【讨论】:

    • 哦。你能发布更多关于如何使用它的代码吗?或某些文章中的示例用法?那会很有帮助。
    【解决方案3】:

    您可以保持 List 私有,而是返回一个 IEnumerable。通过Reflector 生成的代码 - 我希望它是可读的:

    Public Class Core
        Public Sub AddEntry(ByVal Ent As Entry)
            Me.entries.Add(Ent)
        End Sub
    
        Public Sub RemoveEntry(ByVal ID As String)
            Dim pred As Predicate(Of Entry) = Function (ByVal entry As Entry) 
                Return (entry.Id = ID)
            End Function
            Me.entries.RemoveAll(pred)
        End Sub
    
        Public ReadOnly Property Entries As IEnumerable(Of Entry)
            Get
                Return Me.entries
            End Get
        End Property
    
        Private entries As List(Of Entry) = New List(Of Entry)
    End Class
    

    注意:如果您要添加和删除对象,我建议使用 List&lt;Entry&gt; 而不是数组 - 或者考虑到您的使用方式,甚至可能使用 Dictionary&lt;string, Entry&gt;

    【讨论】:

    • 一些聪明人可以将 IEnumerable 属性转换为列表,然后,他可以从该列表中添加/删除对象,而无需使用 AddEntry / RemoveEntry 方法。 :)
    • 当然。除非你做很多额外的工作,否则阻止恶意用户修改底层集合是不现实的。
    • 另一个答案中建议的 ReadOnly 事情怎么样?是否有可能恶意用户也以某种方式绕过它?
    • 是的,如果唯一的保护是让事情变得私密,你总是可以使用反射来绕过它。
    • 您应该在两者之间进行选择,具体取决于您是要允许人们仅像示例中那样迭代元素,还是要索引到数组中。
    猜你喜欢
    • 2015-04-23
    • 2012-09-21
    • 1970-01-01
    • 2021-06-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-02
    • 2016-04-30
    • 1970-01-01
    相关资源
    最近更新 更多