I have the following class:
public class MyCollection<T1, T2> : AnotherCollection<T1>
{
private readonly ICollection<T2> BaseCollection;
public MyCollection(IEnumerable<T1> collection, ICollection<T2> baseCollection) : base(collection)
{
BaseCollection = baseCollection;
}
public MyCollection(List<T1> collection, ICollection<T2> baseCollection) : base(collection)
{
BaseCollection = baseCollection;
}
}
Is there any way to simplify this code such that BaseCollection = baseCollection;
is only written once?
CodePudding user response:
IEnumerable can support both a List and Collection. So you don't need both constructors. With a single constructor like this you can initialize a List and IEnumerable
public class MyCollection<T1, T2> : AnotherClass<T1>
{
private readonly ICollection<T2> BaseCollection;
public MyCollection(IEnumerable<T1> collection, ICollection<T2> baseCollection) : base(collection)
{
BaseCollection = baseCollection;
}
}
Your initial solution is perfectly acceptable, especially if there are different implementations based on type.
If there's a different implementation on the base class for IEnumerable and List, then check something like this, but not recommended
REMEMBER, OVER OPTIMIZATION IS THE ROOT OF ALL EVIL
public class AnotherClass<T1>
{
public AnotherClass(IEnumerable<T1> collection)
{
var type = collection.GetType();
if (type == typeof(IEnumerable<T1>))
{
//Do the implementation Detail for IEnumerable
}
else if (type == typeof(List<T1>))
{
//Do the implementation Detail for List
}
else if (type == typeof(Collection<T1>))
{
//Do the implementation Detail for ICollection
}
else
{
//Do the implementation Detail for Default
}
}
}
CodePudding user response:
You can make the second constructor call the first constructor:
public MyCollection(IEnumerable<T1> collection, ICollection<T2> baseCollection) : base(collection)
{
BaseCollection = baseCollection;
}
public MyCollection(List<T1> collection, ICollection<T2> baseCollection)
: this((IEnumerable<T1>)collection, baseCollection)
{
// you can do additional initialisation for the List<T1> case here
}
Note that it is necessary to convert collection
to IEnumerable<T1>
, so that the call does not resolve to the same constructor again, which is invalid. Other than a cast, you can also use as IEnumerable<T1>
or AsEnumerable()
.
This could be useful if you want some extra stuff to be done when the caller passes in a list, rather than an IEnumerable<T>
. If there's nothing additional that you want to do, you don't actually need two constructors here. List<T1>
implements IEnumerable<T1>
, so you just need the IEnumerable<T1>
one.
If the two base(collection)
calls are actually calling different constructors of the base class (with different implementations), then there are not many choices. All I can think of is to use dynamic
and have only one constructor like this:
public MyCollection(IEnumerable<T1> collection, ICollection<T2> baseCollection) : base((dynamic)collection)
{
BaseCollection = baseCollection;
}
This would make it choose which constructor to call based on the runtime type of the collection passed in. This means that even if you have a List<T1>
, you can't choose to call the IEnumerable<T1>
base constructor by casting it to IEnumerable<T1>
like before. You must create a new IEnumerable
, that is not a List
.