如何编写智能通用集合索引器?

时间:2016-02-26 11:41:16

标签: c# .net vb.net generics types

下面的代码是用Vb.Net编写的,但我也接受了C#解决方案。

我有这些课程:

  • CommandlineParameter(Of T)

    Class CommandlineParameter(Of T)
    End Class
    
  • CommandlineParameter

    Class CommandlineParameter : Inherits CommandlineParameter(Of Object)
    End Class
    
  • CommandlineParameterCollection

    Class CommandlineParameterCollection : Inherits Collection(Of CommandlineParameter)
    End Class
    

CommandlineParameterCollection我添加了一个通用Add方法:

Public Shadows Sub Add(Of T)(ByVal param As CommandlineParameter(Of T))

    If Me.Contains(param.Name) OrElse Me.Contains(param.ShortName) Then
        Throw New ArgumentException(message:="Parameter already exists.", "param")

    Else
        MyBase.Add(param)

    End If

End Sub

然后我以这种方式使用它:

Dim cmds As New CommandlineParameterCollection
With cmds
    .Add(Of String)(Param1)  ' CommandlineParameter(Of String)
    .Add(Of Boolean)(Param2) ' CommandlineParameter(Of Boolean)
End With

现在,问题是,当我调用Indexer时,它返回CommandlineParameterCommandlineParameter(Of Object))然后我需要在源代码周围指定附加的直播来指定它是什么类型,一个例子:

Console.WriteLine(CStr(cmds(Param1).Value))
Console.WriteLine(Cbool(cmds(Param2).Value))

然后为了避免这种情况,我尝试指定一个泛型类型的索引器,但我发现.Net不支持这个。

所以到目前为止我有这个索引器:

Default Public Overloads Property Item(ByVal paramName As String) As CommandlineParameter
    <DebuggerStepThrough>
    Get
        Return Me.Find(paramName)
    End Get
    <DebuggerStepThrough>
    Set(ByVal value As CommandlineParameter)
        Me(Me.IndexOf(paramName)) = value
    End Set
End Property

有什么解决方案可以避免额外的强制转换并返回我想要的类型的值?

我将澄清CommandlineParameterCommandlineParameter(Of Object))类根本没有必要,如果解决方案暗示删除它,那么我可以删除它,因为我设计它只是为了使用更友好那个对象。

1 个答案:

答案 0 :(得分:1)

由于Collection<T>假定每个项目都具有相同的T,因此您无法将CommandlineParameter<string>CommandlineParameter<bool>存储在同一Collection<T>中。

IMO,你能做的最好是模仿这样的收集行为:

class CommandLineParameter<T> { }
class CommandlineParameterCollection
{
    // use most common type to store items in inner collection - object
    private readonly List<object> inner;

    public void Add<T>(CommandLineParameter<T> value)
    {
        inner.Add(value);
    }

    public void Remove<T>(CommandLineParameter<T> value)
    {
        inner.Remove(value);
    }

    public CommandLineParameter<T> GetAt<T>(int index)
    {
        // will throw InvalidCastException if T at given index doesn't match passed T
        return (CommandLineParameter<T>)inner[index];
    }
}