.net - 在没有重复成员的情况下实现通用和非通用接口
问题描述
前提
像Enum
这样:
Public Enum Foo
A
B
C
End Enum
我想创建一个类来跟踪Foo
内部存在哪些值HashSet(Of Foo)
并将数据公开为IDictionary(Of Foo, Boolean)
. 该类还需要实现非泛型IDictionary
接口(这是我的用例所要求的)。
Public Class FooTracker
Implements IDictionary, IDictionary(Of Foo, Boolean)
Private foos As HashSet(Of Foo)
...
End Class
FooTracker
where foos
contains only的期望行为B
是FooTracker(Foo.A)
并且FooTracker(Foo.C)
应该在返回False
时都FooTracker(Foo.B)
返回True
。
问题
IDictionary<TKey, TValue>
并且IDictionary
具有应该由同一成员合理实现FooTracker
但具有不同签名的成员。我们以Item
房产为例。
IDictionary
想要Default Public Property Item(key As Object) As Object Implements IDictionary.Item
IDictionary<Foo, Boolean>
想要Default Public Property Item(key As Foo) As Boolean Implements IDictionary(Of Foo, Boolean).Item
我不想实现两个单独的属性,一个只调用另一个,因为那是很多无用的样板代码。更重要的是,我不希望泛型和非泛型版本都显示为重载。
看一下标准Dictionary(TKey, TValue)
类(不是接口)。当您Item
在 Visual Studio 中访问该属性时,您获得的唯一选项是通用Item(key as TKey)
. 尽管实现了非泛型,但它不会向您显示Item(key as Object)
事件。但它是如何做到的呢?他们如何只有一个成员同时实现and ?Dictionary(TKey, TValue)
IDictionary
IDictionary.Item
IDictioanry<TKey, TValue>.Item
解决方案
我想到了。我缺少的是我不知道您可以将接口成员实现为Private
,这可以防止通过实现类型调用它,但仍然允许通过接口类型调用它。
对于遇到同样问题的任何人,这里是使用我的示例的完整示例实现FooTracker
。请注意,这是一个固定大小字典的示例,这就是为什么所有Add
和Remove
方法都被隐藏并在调用时抛出异常的原因。
Public Class FooTracker
Implements IDictionary, IDictionary(Of Foo, Boolean)
Private foos As HashSet(Of Foo)
Private Shared allFooValues As New ReadOnlyCollection(Of Foo)([Enum].GetValues(GetType(Foo)))
Default Public Property Item(key As Foo) As Boolean Implements IDictionary(Of Foo, Boolean).Item
Get
Return foos.Contains(key)
End Get
Set(value As Boolean)
If value Then
foos.Add(key)
Else
foos.Remove(key)
End If
End Set
End Property
Private Property IDictionary_Item(key As Object) As Object Implements IDictionary.Item
Get
Return Item(key)
End Get
Set(value As Object)
Item(key) = value
End Set
End Property
Public ReadOnly Property Keys As ICollection(Of Foo) Implements IDictionary(Of Foo, Boolean).Keys
Get
Return allFooValues
End Get
End Property
Private ReadOnly Property IDictionary_Keys As ICollection Implements IDictionary.Keys
Get
Return Keys
End Get
End Property
Public ReadOnly Property Values As ICollection(Of Boolean) Implements IDictionary(Of Foo, Boolean).Values
Get
Return allFooValues.Select(Function(F) Item(F))
End Get
End Property
Private ReadOnly Property IDictionary_Values As ICollection Implements IDictionary.Values
Get
Return Values
End Get
End Property
Public ReadOnly Property IsReadOnly As Boolean Implements IDictionary.IsReadOnly, ICollection(Of KeyValuePair(Of Foo, Boolean)).IsReadOnly
Get
Return False
End Get
End Property
Public ReadOnly Property IsFixedSize As Boolean Implements IDictionary.IsFixedSize
Get
Return True
End Get
End Property
Private Sub ThrowNotSupportedException()
Throw New NotSupportedException()
End Sub
Public ReadOnly Property Count As Integer Implements ICollection.Count, ICollection(Of KeyValuePair(Of Foo, Boolean)).Count
Get
Return allFooValues.Count
End Get
End Property
Public ReadOnly Property SyncRoot As New Object Implements ICollection.SyncRoot
Public ReadOnly Property IsSynchronized As Boolean Implements ICollection.IsSynchronized
Get
Return False
End Get
End Property
Private Sub Add(key As Foo, value As Boolean) Implements IDictionary(Of Foo, Boolean).Add
ThrowNotSupportedException()
End Sub
Private Sub IDictionary_Add(key As Object, value As Object) Implements IDictionary.Add
ThrowNotSupportedException()
End Sub
Private Sub ICollection_Add(item As KeyValuePair(Of Foo, Boolean)) Implements ICollection(Of KeyValuePair(Of Foo, Boolean)).Add
ThrowNotSupportedException()
End Sub
Public Sub Clear() Implements IDictionary.Clear
foos.Clear()
End Sub
Private Sub ICollection_Clear() Implements ICollection(Of KeyValuePair(Of Foo, Boolean)).Clear
Clear()
End Sub
Private Function Remove(key As Foo) As Boolean Implements IDictionary(Of Foo, Boolean).Remove
ThrowNotSupportedException()
End Function
Private Sub IDictionary_Remove(key As Object) Implements IDictionary.Remove
ThrowNotSupportedException()
End Sub
Private Function ICollection_Remove(item As KeyValuePair(Of Foo, Boolean)) As Boolean Implements ICollection(Of KeyValuePair(Of Foo, Boolean)).Remove
ThrowNotSupportedException()
End Function
Public Sub CopyTo(array() As KeyValuePair(Of Foo, Boolean), arrayIndex As Integer) Implements ICollection(Of KeyValuePair(Of Foo, Boolean)).CopyTo
For i As Integer = 0 To allFooValues.Count - 1
Dim F = allFooValues(i)
array(arrayIndex + i) = New KeyValuePair(Of Foo, Boolean)(F, Item(F))
Next
End Sub
Private Sub ICollection_CopyTo(array As Array, index As Integer) Implements ICollection.CopyTo
CopyTo(array, index)
End Sub
Public Function Contains(item As KeyValuePair(Of Foo, Boolean)) As Boolean Implements ICollection(Of KeyValuePair(Of Foo, Boolean)).Contains
Return Me.Item(item.Key) = item.Value
End Function
Private Function IDictionary_Contains(key As Object) As Boolean Implements IDictionary.Contains
Return Contains(key)
End Function
Public Function ContainsKey(key As Foo) As Boolean Implements IDictionary(Of Foo, Boolean).ContainsKey
Return allFooValues.Contains(key)
End Function
Public Function TryGetValue(key As Foo, ByRef value As Boolean) As Boolean Implements IDictionary(Of Foo, Boolean).TryGetValue
value = Item(key)
Return True
End Function
Public Function GetEnumerator() As Enumerator
Return New Enumerator(Me)
End Function
Private Function IDictionary_GetEnumerator() As IDictionaryEnumerator Implements IDictionary.GetEnumerator
Return GetEnumerator()
End Function
Private Function IEnumerable_GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator
Return GetEnumerator()
End Function
Private Function IEnumerable2_GetEnumerator() As IEnumerator(Of KeyValuePair(Of Foo, Boolean)) Implements IEnumerable(Of KeyValuePair(Of Foo, Boolean)).GetEnumerator
Return GetEnumerator()
End Function
Public Class Enumerator
Implements IEnumerator(Of KeyValuePair(Of Foo, Boolean)), IDictionaryEnumerator
Private tracker As FooTracker
Private nextIndex As Integer
Private currentItem As KeyValuePair(Of Foo, Boolean)
Friend Sub New(tracker As FooTracker)
Me.tracker = tracker
End Sub
Public Function MoveNext() As Boolean Implements IEnumerator.MoveNext
If nextIndex < allFooValues.Count Then
Dim F = allFooValues(nextIndex)
_Current = New KeyValuePair(Of Foo, Boolean)(F, tracker(F))
nextIndex += 1
Return True
Else
_Current = New KeyValuePair(Of Foo, Boolean)()
Return False
End If
End Function
Public ReadOnly Property Current As KeyValuePair(Of Foo, Boolean) Implements IEnumerator(Of KeyValuePair(Of Foo, Boolean)).Current
Private ReadOnly Property IEnumerator_Current As Object Implements IEnumerator.Current
Get
Return Current
End Get
End Property
Public Sub Reset() Implements IEnumerator.Reset
nextIndex = 0
_Current = New KeyValuePair(Of Foo, Boolean)()
End Sub
Public ReadOnly Property Key As Object Implements IDictionaryEnumerator.Key
Get
Return Current.Key
End Get
End Property
Public ReadOnly Property Value As Object Implements IDictionaryEnumerator.Value
Get
Return Current.Value
End Get
End Property
Public ReadOnly Property Entry As DictionaryEntry Implements IDictionaryEnumerator.Entry
Get
Return New DictionaryEntry(Current.Key, Current.Value)
End Get
End Property
Private Sub Dispose() Implements IDisposable.Dispose
End Sub
End Class
End Class
如果您声明一个 type 变量FooTracker
,则只有泛型Item
属性是可访问的。但是您可以强制FooTracker
转换为IDictionary
,这允许您访问非泛型Item
属性。
推荐阅读
- javascript - Lodash:无法通过自定义谓词进行过滤,包含匹配属性和函数
- python - OpenCV:从外部轮廓中删除轮廓
- html - 嵌入在我的 HTML 页面中的 GitHub 源代码?
- c++ - 如何从头文件的界面中隐藏“帮助函数”
- r - R中所有NA的最后一次观察结转(LOCF)
- javascript - Javascript 将 div 内容设置为 iframe
- flutter - 对 Firestore 不均匀段错误感到困惑
- go - 如何阅读软件包文档
- android - Google Pay 不显示总价或 displayItems
- javascript - React Search - 我正在尝试创建一个过滤器,但它不起作用