I have a class like the following for holding multiple objects.
At the Moment it is Possible to get Objects with .Get<T>()
.
I want to be able to get the objects by casting the MultiHolder<...>
MultiHolder<IHolderA, IHolderB, IHolderC> multiHolder = new MultiHolder<IHolderA, IHolderB, IHolderC>(new HolderA(), new HolderB(), new HolderC());
//Works
IHolderA HolderA_byGet = multiHolder.Get<IHolderA>();
//Works??!
IHolderB HolderB_byExplicitCast = (HolderB)multiHolder;
//Throws InvalidCastException
IHolderB HolderB_byEcplicitInterfaceCast = (IHolderB)multiHolder;
//Will not compile
//HolderC HolderC_byImplicitCast = multiHolder;
//Will not compile
//IHolderC HolderC_byImplicitInterfaceCast = multiHolder;
I first tried to cast it to IHolderB
. Resulting in an InvalidCastException
. Why wont it use the implicit cast?
While testing i discovered that casting it to 'HolderB' will work. Why does this work when Tholder2
is IHolderB
.
Also, why am i not able to use implicit cassts, even though they are defined as such?
Following code, for compleate example:
using System;
using System.Collections.Generic;
namespace MultiHolderExample
{
public interface IHolder{}
public abstract class MultiHolder : IHolder
{
private readonly Dictionary<Type, IHolder> _holders;
protected MultiHolder(Type[] types, IHolder[] holders)
{
_holders = new Dictionary<Type, IHolder>();
for (int i = 0; i < types.Length; i++)
{
if (!types[i].IsInstanceOfType(holders[i]))
throw new ArgumentException($"Can't convert \"{holders[i].GetType().Name}\" to \"{types[i].Name}\"");
_holders.Add(types[i], holders[i]);
}
}
public T Get<T>() where T : IHolder
{
if (_holders.TryGetValue(typeof(T), out IHolder holder))
return (T)holder;
throw new ArgumentException("Unknown Type of holder " + typeof(T).Name);
}
}
#region Generic holders
public class MultiHolder<Tholder1, Tholder2> : MultiHolder
where Tholder1 : IHolder
where Tholder2 : IHolder
{
#region Constructor
public MultiHolder(Tholder1 f1, Tholder2 f2) :
base(new[] { typeof(Tholder1), typeof(Tholder2) }, new IHolder[] { f1, f2 })
{ }
public static implicit operator Tholder1(MultiHolder<Tholder1, Tholder2> holder) => holder.Get<Tholder1>();
public static implicit operator Tholder2(MultiHolder<Tholder1, Tholder2> holder) => holder.Get<Tholder2>();
#endregion
}
public class MultiHolder<Tholder1, Tholder2, Tholder3> : MultiHolder
where Tholder1 : IHolder
where Tholder2 : IHolder
where Tholder3 : IHolder
{
#region Constructor
public MultiHolder(Tholder1 f1, Tholder2 f2, Tholder3 f3) :
base(new[] { typeof(Tholder1), typeof(Tholder2), typeof(Tholder3) }, new IHolder[] { f1, f2, f3 })
{ }
public MultiHolder(MultiHolder<Tholder1, Tholder2> mf1, Tholder3 f3) :
base(new[] { typeof(Tholder1), typeof(Tholder2), typeof(Tholder3) }, new IHolder[] { mf1.Get<Tholder1>(), mf1.Get<Tholder2>(), f3 })
{ }
public static implicit operator Tholder1(MultiHolder<Tholder1, Tholder2, Tholder3> holder) => holder.Get<Tholder1>();
public static implicit operator Tholder2(MultiHolder<Tholder1, Tholder2, Tholder3> holder) => holder.Get<Tholder2>();
public static implicit operator Tholder3(MultiHolder<Tholder1, Tholder2, Tholder3> holder) => holder.Get<Tholder3>();
#endregion
}
#endregion
public interface IHolderA : IHolder { }
public class HolderA : IHolderA { public int HolderAVal; }
public interface IHolderB : IHolder { }
public class HolderB : IHolderB { public int HolderBVal; }
public interface IHolderC : IHolder { }
public class HolderC : IHolderC { public int HolderCVal; }
}