【问题标题】:Create Indexer in VB.NET which can be used from C#在 VB.NET 中创建可以从 C# 使用的索引器
【发布时间】:2011-08-24 22:09:16
【问题描述】:

我可以在 VB.NET 中创建一个可以像这样从 C# 中使用的类吗:

myObject.Objects[index].Prop = 1234;

当然,我可以创建一个返回数组的属性。但要求是索引是从 1 开始的,而不是从 0 开始的,所以这个方法必须以某种方式映射索引:

我试图让它这样,但 C# 告诉我我不能直接调用它:

   Public ReadOnly Property Objects(ByVal index As Integer) As ObjectData
        Get
            If (index = 0) Then
                Throw New ArgumentOutOfRangeException()
            End If
            Return parrObjectData(index)
        End Get
    End Property

编辑 对不起,如果我有点不清楚:

C# 只允许我像这样调用这个方法

myObject.get_Objects(index).Prop = 1234

但不是

myObject.Objects[index].Prop = 1234;

这就是我想要达到的目标。

【问题讨论】:

  • Default 是您缺少的关键字。布赖恩的回答已经涵盖了你。
  • 您要求的是索引属性,这是 C# 中不直接提供的功能。

标签: c# .net vb.net indexer language-interoperability


【解决方案1】:

语法是:

Default Public ReadOnly Property Item(ByVal index as Integer) As ObjectData
  Get
    If (index = 0) Then
      Throw New ArgumentOutOfRangeException()
    End If
    Return parrObjectData(index)
  End Get
End Property

Default 关键字是创建索引器的魔法。不幸的是,C# 不支持命名索引器。您将不得不创建一个自定义集合包装器并将其返回。

Public ReadOnly Property Objects As ICollection(Of ObjectData)
  Get
    Return New CollectionWrapper(parrObjectData)
  End Get
End Property

CollectionWrapper 可能如下所示:

Private Class CollectionWrapper
  Implements ICollection(Of ObjectData)

  Private m_Collection As ICollection(Of ObjectData)

  Public Sub New(ByVal collection As ICollection(Of ObjectData))
    m_Collection = collection
  End Sub

  Default Public ReadOnly Property Item(ByVal index as Integer) As ObjectData
    Get
      If (index = 0) Then
        Throw New ArgumentOutOfRangeException()
      End If
      Return m_Collection(index)
    End Get
  End Property

End Class

【讨论】:

  • 如果我希望该属性具有 Item 以外的名称?
  • 您忘记了“property”关键字。
【解决方案2】:

您可以在 C# 中使用带有默认索引器的结构来伪造命名索引器:

public class ObjectData
{
}

public class MyClass
{
    private List<ObjectData> _objects=new List<ObjectData>();
    public ObjectsIndexer Objects{get{return new ObjectsIndexer(this);}}

    public struct ObjectsIndexer
    {
        private MyClass _instance;

        internal ObjectsIndexer(MyClass instance)
        {
            _instance=instance;
        }

        public ObjectData this[int index]
        {
            get
            {
                return _instance._objects[index-1];
            }
        }
    }
}

void Main()
{
        MyClass cls=new MyClass();
        ObjectData data=cls.Objects[1];
}

如果这是一个好主意是另一个问题。

【讨论】:

  • 重要的是要注意,只有当您的 ObjectData 对象是一个类时,这才是一个很好的解决方案。如果它是一个结构,您将无法在 ObjectsIndexer 中存储对它的引用(充其量您可以获得一份副本)。这使得使用这种模式来包装带有固定缓冲区的不安全结构存在问题,因为您不能在类中使用固定缓冲区,也不能让 ObjectsIndexer 指向结构。
【解决方案3】:

C# 不支持 named 索引属性的声明(尽管您可以创建索引器),但您可以通过显式调用 setter 或 getter 来访问用其他语言(如 VB)声明的索引属性(get_MyProperty/set_MyProperty)

【讨论】:

    【解决方案4】:

    为什么不使用基于 0 的索引,而是让编码人员错觉它是基于 1 的?

    Return parrObjectData(index-1)
    

    【讨论】:

    • 方法签名应该是什么样子的?
    • 和它一样,这应该是唯一应该改变的行。除了删除 (index = 0) if 语句块
    • 但我的问题是,使用当前的方法签名,VB.NET 不允许我调用 myObject.Objects[index] 之类的方法
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-08
    • 2013-03-29
    • 1970-01-01
    • 2011-02-11
    相关资源
    最近更新 更多