为什么我的接口方法调用在C#泛型中被忽略?

时间:2018-03-09 17:41:01

标签: c# generics interface

我对C#很新,我无法理解项目中类的行为。

我使用的接口定义了一个带有类型约束的泛型,这是另一个接口。

当我调用泛型时,我知道参数上存在某个方法(因为类型约束),但是当我调用它时,这个方法不会被执行。

到目前为止,我唯一的解决方法是将方法调用包含在特定于类型的方法重载中。

使用具有等效类型结构的以下代码段可以更好地解释这一点:

public interface ITrickable
{
    void GetRabbitOut();
}

public interface IMagic
{
    void DoTricks<T>(T obj) where T : ITrickable;
}

public class Hat : ITrickable
{
    public void LiftUp() { Console.WriteLine("Lifting up the hat..."); }
    public void GetRabbitOut() { Console.WriteLine("A rabbit came out the hat !"); }
}

public class Box : ITrickable
{
    public void OpenDoubleBottom() { Console.WriteLine("Opening the box..."); }
    public void GetRabbitOut() { Console.WriteLine("A rabbit came out the box !"); }
}

public abstract class Magician : IMagic
{
    public abstract void DoTricks<T>(T obj) where T : ITrickable;
}

现在,如果我使用以下课程致电DoTricks(new Hat()); DoTricks(new Box());

public class Houdini : Magician
{
    public override void DoTricks<T>(T obj)
    {
        try {
            DoTricks(obj); }
        catch {
            throw new NotImplementedException(); }
    }

    public void DoTricks(Hat obj)
    {
        obj.LiftUp();
        obj.GetRabbitOut();
    }

    public void DoTricks(Box obj)
    {
        obj.OpenDoubleBottom();
        obj.GetRabbitOut();
    }
}

输出符合预期:

Lifting up the hat...
A rabbit came out the hat !
Opening the box...
A rabbit came out the box !

但是如果这个类定义如下:

public class Genesta : Magician
{
    public override void DoTricks<T>(T obj)
    {
        try {
            DoTricks(obj);
            obj.GetRabbitOut(); }  //  <--- This seems to be ignored !?
        catch {
            throw new NotImplementedException(); }
    }

    public void DoTricks(Hat obj)
    {
        obj.LiftUp();
    }

    public void DoTricks(Box obj)
    {
        obj.OpenDoubleBottom();
    }
}

输出

Lifting up the hat...
Opening the box...

问题是为什么在{2}中没有调用GetRabbitOut

编辑:主叫代码为:

public static void Main(string[] args)
{
    var houdini = new Houdini();
    var hat = new Hat();
    var box = new Box();

    houdini.DoTricks(hat);
    houdini.DoTricks(box);
    Console.ReadLine();
}

1 个答案:

答案 0 :(得分:1)

注意你的方法调用(我想它看起来像这样):

Genesta g = new Genesta();
g.DoTricks(new Hat()); 
g.DoTricks(new Box());

由于您调用g.DoTricks(new Hat())而不是g.DoTricks<Hat>(new Hat()),因此调用Genesta类的确切方法为DoTricks(T obj)而非DoTricks<T>(T obj)并不令人惊讶。在考虑DoTricks(T obj) ...

的实施时
public void DoTricks(Hat obj)
{
    obj.LiftUp();
}

public void DoTricks(Box obj)
{
    obj.OpenDoubleBottom();
}

结果实际上是您对这些方法的期望!

但是,如果您要调用这样的通用方法......

g.DoTricks<Hat>(new Hat());

您将陷入无限递归,因为该方法会无限期地调用自身。 DoTricks<T>(T obj)将始终调用自身,而不是专门的重载DoTricks(Hat)DoTricks(Box)之一,因为编译器在运行时之前无法知道T实际上是Hat或Box。 顺便说一句,Houdini类经历了同样的效果 - 恰好它的特定DoTricks(Hat)DoTricks(Box)方法会产生您通过调用DoTricks<T>(T obj)所期望的结果。