代码之家  ›  专栏  ›  技术社区  ›  Jacques Gaudin

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

  •  1
  • Jacques Gaudin  · 技术社区  · 7 年前

    我对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...
    

    问题是为什么 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 回复  |  直到 7 年前
        1
  •  1
  •   JonyVol    7 年前

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

    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(帽子) DoTricks(框) 方法生成您期望的调用结果 DoTricks<T>(T obj)