Have a complex visitor scenario with constrained interface:
public enum EDTypes { A1, A2 }
public interface IProcing { string doIt(string value); }
public interface IFooIni : IProcing { }
public interface IFooEnd : IProcing { }
public class FooIni_A1 : IFooIni { public string doIt(string value) { return "itsIni_A01"; } }
public class FooEnd_A1 : IFooEnd { public string doIt(string value) { return "itsEnd_A01"; } }
public class FooIni_A2 : IFooIni { public string doIt(string value) { return "itsIni_A02"; } }
public class FooEnd_A2 : IFooEnd { public string doIt(string value) { return "itsEnd_A02"; } }
public interface IFooSet<H, T> : IProcing
where H : IFooIni
where T : IFooEnd
{
H FooIni { get; set; }
List<IProcing> FooBar { get; set; }
T FooEnd { get; set; }
}
and multiples concrete implementations:
public class FooSet_A1 : IFooSet<FooIni_A1, FooEnd_A1>
{
public FooIni_A1 FooIni { get; set; }
public List<IProcing> FooBar { get; set; }
public FooEnd_A1 FooEnd { get; set; }
public string doIt(string value) { return "itsIni_FooSetA1"; }
}
public class FooSet_A2 : IFooSet<FooIni_A2, FooEnd_A2>
{
public FooIni_A2 FooIni { get; set; }
public List<IProcing> FooBar { get; set; }
public FooEnd_A2 FooEnd { get; set; }
public string doIt(string value) { return "itsIni_FooSetA2"; }
}
why cant do:
public class testfoo
{
private IFooSet<IFooIni, IFooEnd> getInstance(EDTypes type)
{
IFooSet<IFooIni, IFooEnd> res = null;
switch (type)
{
case EDTypes.A1:
/*
Unable to cast object of type
'_protoTest.FooSet_A1'
to type
'_protoTest.IFooSet`2[_protoTest.IFooIni,_protoTest.IFooEnd]'.
*/
res = (IFooSet<IFooIni, IFooEnd>)new FooSet_A1();
break;
case EDTypes.A2:
res = (IFooSet<IFooIni, IFooEnd>)new FooSet_A2();
break;
}
return res;
}
public void testIt()
{
// +*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*
IFooSet<IFooIni, IFooEnd> A1 = (IFooSet<IFooIni, IFooEnd>)getInstance(EDTypes.A1);
string x = A1.doIt("ASDFG");
// +*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*
}
}
Someone here telling to create another interface above, but I need the problematic interface structure on my factory result.
@Eldritch Conundrum told me about "covariance on T" and helped me a
lot get what is happening.
I cant get yet a solution to this problem and getting crazy with the deadline
but my question was "why" its happening and he explained very well.
Putting more detail. Marking as answer.
After last coment of @Eldritch Conundrum i used dynamic keyword and solved my problem.
I losted all intellisense but its work now !!!
Thanks @Eldritch Conundrum
There is the code :
*public enum EDTypes { A1, A2 }
public interface IProcing { string doIt(string value); }
public interface IFooIni : IProcing { }
public interface IFooEnd : IProcing { }
public class FooIni_A1 : IFooIni { public string doIt(string value) { return "itsIni_A01"; } }
public class FooEnd_A1 : IFooEnd { public string doIt(string value) { return "itsEnd_A01"; } }
public class FooIni_A2 : IFooIni { public string doIt(string value) { return "itsIni_A02"; } }
public class FooEnd_A2 : IFooEnd { public string doIt(string value) { return "itsEnd_A02"; } }
public interface IFooSet<H, T> : IProcing
where H : IFooIni
where T : IFooEnd
{
H FooIni { get; set; }
List<IProcing> FooBar { get; set; }
T FooEnd { get; set; }
}
public class FooSet_A1 : IFooSet<FooIni_A1, FooEnd_A1>
{
public FooIni_A1 FooIni { get; set; }
public List<IProcing> FooBar { get; set; }
public FooEnd_A1 FooEnd { get; set; }
public string doIt(string value) { return "itsIni_FooSetA1"; }
}
public class FooSet_A2 : IFooSet<FooIni_A2, FooEnd_A2>
{
public FooIni_A2 FooIni { get; set; }
public List<IProcing> FooBar { get; set; }
public FooEnd_A2 FooEnd { get; set; }
public string doIt(string value) { return "itsIni_FooSetA2"; }
}
public class testfoo
{
private IProcing getInstance(EDTypes type)
{
dynamic res = null;
switch (type)
{
case EDTypes.A1:
res = new FooSet_A1();
break;
case EDTypes.A2:
res = new FooSet_A2();
break;
}
return res;
}
public void testIt()
{
// +*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*
dynamic A1 = getInstance(EDTypes.A1);
string s1 = A1.doIt("ASDFG");
dynamic A2 = getInstance(EDTypes.A2);
string s2 = A2.doIt("ASDFG");
// +*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*
}
}*
So, you want to convert an IConstrained<CtrA1, CtrB1, CtrC1>
to an IConstrained<IClassA, IClassB, IClassC>
because CtrA1
implements IClassA
(and similarly for the others).
This is a bit like converting an IEnumerable<string>
to an IEnumerable<object>
.
.Net allows it because IEnumerable<T>
is actually declared as IEnumerable<out T>
. This called covariance on T.
However, this won't work for you if your IConstrained<>
has methods that take an IClassA
, because that would be unsafe. Can you see why?
Casting an IEnumerable<string>
to an IEnumerable<object>
is safe because one can only ever read strings/objects from IEnumerable
.
But for a List<T>
, it wouldn't work, because a List<string>
casted into a List<object>
would enable you to add an object into the list (of strings!).