无法将具体实现强制转换为约束类型的实现接口

时间:2013-07-05 18:54:29

标签: c#-4.0 design-patterns generics casting type-constraints

具有受限界面的复杂访问者场景:

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 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");
        // +*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*
    }
}

有人here告诉上面创建另一个界面,但我需要在我的工厂结果上有问题的界面结构。


@Eldritch难题告诉我关于“T的协方差”并帮助了我 很多事情发生了。
我无法解决这个问题,并在截止日期前发疯 但我的问题是“为什么”它的发生,他解释得非常好 提供更多细节。标记为答案。

非常感谢

在@Eldritch Conundrum的最后一次讽刺后,我使用了动态关键字并解决了我的问题 我失去了所有intellisense但它的工作现在! 谢谢@Eldritch难题
有代码:

*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");
        // +*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*
    }
}*

1 个答案:

答案 0 :(得分:1)

因此,您希望将IConstrained<CtrA1, CtrB1, CtrC1>转换为IConstrained<IClassA, IClassB, IClassC>因为CtrA1实现了IClassA(对其他人来说也是如此)。

这有点像将IEnumerable<string>转换为IEnumerable<object>

.Net允许它,因为IEnumerable<T>实际上被声明为IEnumerable<out T>。这在T上称为协方差

但是,如果IConstrained<>的方法采用IClassA,这对您不起作用,因为这样会不安全。你能明白为什么吗?

IEnumerable<string>投射到IEnumerable<object>是安全的,因为只能从IEnumerable读取字符串/对象。 但是对于List<T>,它不起作用,因为List<string>转换为List<object>会使您能够将对象添加到列表中(字符串!)。