Вопрос

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.

Thanks a lot

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!).

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top