返回通用接口时出错

时间:2013-04-11 11:36:03

标签: c# generics inheritance

以下代码是我正在编写的程序的一个简单示例。

public class Y
{ }

public class X : Y
{ }

public class W : Y
{ }

public interface IAaa<T>
    where T : Y
{
    void Execute(T ppp);
}

public abstract class Aaa<T> : IAaa<T>
    where T : Y
{
    public abstract void Execute(T ppp);
}

public class Bbb : Aaa<X>
{
    public override void Execute(X ppp)
    { }
}

public class Ccc : Aaa<W>
{
    public override void Execute(W ppp)
    { }
}

public class Factory 
{
    public static IAaa<Y> Get(bool b)
    {
        if(b)
            return new Bbb();
        else
            return new Ccc();
    }
}

class Program
{
    static void Main(string[] args)
    {
        IAaa<Y> aa;
        aa = Factory.Get(true);
    }
}

当我编译它时,我得到以下错误

  

错误CS0266:无法隐式转换类型'ConsoleApplication3.Bbb'   到'ConsoleApplication3.IAaa'。一个明确的   存在转换(你错过了演员吗?)

     

错误CS0266:无法隐式转换类型'ConsoleApplication3.Ccc'   到'ConsoleApplication3.IAaa'。一个明确的   存在转换(你错过了演员吗?)

有没有办法让它发挥作用?

3 个答案:

答案 0 :(得分:1)

您无法以您尝试的方式使用该界面。查找covariance/contravariance,您尝试与可能的相反(您在界面中可能<in T>,但您尝试使用<out T>)。

以课程Bbb为例 - 它有一个Execute(X)方法。如果您尝试传递Y(可能是X可能不是IAaa),会发生什么?编译器不允许它,因为你从未在代码中定义在这种情况下会发生什么。

您可以通过创建和实施另一个界面public interface IAaa { void Execute(Y ppp); } 来执行您想要的操作。 E.g。

void Main()
{
        IAaa aa;
        aa = Factory.Get(true);
}

public class Y
{ }

public class X : Y
{ }

public class W : Y
{ }

public interface IAaa<T> : IAaa
    where T : Y
{
    void Execute(T ppp);
}

public interface IAaa
{
    void Execute(Y ppp);
}

public abstract class Aaa<T> : IAaa<T>
    where T : Y
{
    public abstract void Execute(T ppp);
    void IAaa.Execute(Y ppp)
    {
        this.Execute(ppp);
    }
    protected abstract void Execute(Y ppp);
}

public class Bbb : Aaa<X>
{
    public override void Execute(X ppp)
    { }
    protected override void Execute(Y ppp)
    {
        this.Execute((X)ppp);
    }
}

public class Ccc : Aaa<W>
{
    public override void Execute(W ppp)
    { }
    protected override void Execute(Y ppp)
    {
        this.Execute((W)ppp);
    }
}

public class Factory 
{
    public static IAaa Get(bool b)
    {
        if(b)
            return new Bbb();
        else
            return new Ccc();
    }
}

也许是这样实现的,所以如果你尝试用无效的类型调用它,就会抛出一个强制转换异常:

{{1}}

答案 1 :(得分:0)

正如错误所说,你错过了演员。我相信这就是你所需要的:

public static IAaa<Y> Get(bool b)
{
    if(b)
        return (IAaa<Y>)(new Bbb());
    else
        return (IAaa<Y>)(new Ccc());
}

答案 2 :(得分:0)

您可以转换为(IAaa<Y>)并且您的代码将被编译。 但是它不起作用,并且在运行时会失败。 为什么? 您的类BbbCcc是专用类,Execute方法无法处理所有类型的Aaa。你必须告诉C#/编译器。

<强>更新

通过拥有通用工厂,您可以获得IAaa的专用实例,并且您的代码应该可以工作。 在Program中,当您向工厂传递TRUE或FALSE时,您已经知道了类型,因此您需要明确告诉C#您要使用的接口实现的类型。 (相应地重构Factory类,我只是发送应编译的内容)

public class Y
{ }

public class X : Y
{ }

public class W : Y
{ }

public interface IAaa<T>
    where T : Y
{
    void Execute(T ppp);
}

public abstract class Aaa<T> : IAaa<T>
    where T : Y
{
    public abstract void Execute(T ppp);
}

public class Bbb : Aaa<X>
{
    public override void Execute(X ppp)
    { }
}

public class Ccc : Aaa<W>
{
    public override void Execute(W ppp)
    { }
}

public class Factory<T> where T : Y
{
    public static IAaa<T> Get(bool b)
    {
        if(b)
            return (IAaa<T>)new Bbb();
        else
            return (IAaa<T>)new Ccc();
    }
}

class Program
{
    static void Main(string[] args)
    {
        IAaa<X> aa;
        aa = Factory<X>.Get(true);
    }
}

更新2

只是一个如何重构Factory类的例子:

public class Factory<T, U>
    where T : Y
    where U : Aaa<T>, new()
{
    public static IAaa<T> Get()
    {
        return (IAaa<T>)new U();
    }
}

class Program
{
    static void Main(string[] args)
    {
        IAaa<X> aa;
        aa = Factory<X, Bbb>.Get();
    }
}