ElektroStudios
ElektroStudios

Reputation: 20464

How to write a smart generic collection Indexer?

The code below is written in Vb.Net but I accept a C# solution too.


I have these classes:

In the CommandlineParameterCollection I added a generic Add method:

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

Then I use it in this way:

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

Now, the problem is that when I call the Indexer, it returns me a CommandlineParameter (CommandlineParameter(Of Object)) then I need to specify additionals directcasts around my source-code to specify what type it is, an example:

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

Then to avoid this, I tried to specify a generic type Indexer but I discovered that .Net doesn't support this.

So by the moment I have this indexer:

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

What solution exists for this to avoid the additional casts and return a value of the type I want?

I will clarify that the CommandlineParameter ( CommandlineParameter(Of Object) ) class is not necessary at all, If a solution implies delete it then I can delete it, because I designed it just to make more friendly the usage of that object.

Upvotes: 0

Views: 105

Answers (1)

Dennis
Dennis

Reputation: 37770

Since Collection<T> assumes, that every item has the same T, you can't store CommandlineParameter<string> and CommandlineParameter<bool> in the same Collection<T>.

IMO, best you can do here is to mimic collection behavior like this:

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];
    }
}

Upvotes: 1

Related Questions