代码之家  ›  专栏  ›  技术社区  ›  LePioo

C#函数的委托,没有返回值和一个允许子类型类的参数(作为参数)

  •  2
  • LePioo  · 技术社区  · 8 年前

    我正在寻找一个委托,它封装了一个方法,该方法不返回任何值,只接受一个参数,如 是的,但不幸的是,该委托与采用 作为参数。。。

    public class BaseType
    {
        public BaseType()
        {
    
        }
    }
    public class ChildType : BaseType
    {
        public ChildType()
        {
    
        }
    }
    public class Test
    {
    
    public delegate void CallBackHandler(BaseType p);
    
        public Test()
        {
            CallBackHandler clbk1 = callBackA;
            CallBackHandler clbk2 = callBackB;   //That line does not compile
                                                 //->'No overload for 'callBackB' matches delegate 'Test.CallBackHandler'
        }
    
        private void callBackA(BaseType p)
        {
    
        }
    
        private void callBackB(ChildType p)
        {
    
        }
    }
    

    我读过关于协方差,逆变,等等…我知道它涉及herited类型铸造,但我对所有这些有点困惑。。。

    我应该使用哪个委托使代码工作?

    3 回复  |  直到 8 年前
        1
  •  1
  •   hoodaticus    8 年前

    这是创建强类型来解决的经典类型安全问题。

    abstract class Vehicle
    {
        public virtual void MethodSlot1_StartEngine() { }
    
        public virtual void MethodSlot2_StopEngine() { }
    }
    
    class Car : Vehicle
    {
        public virtual void MethodSlot3_OpenGasTank() { }
    }
    
    class NuclearSubmarine : Vehicle
    {
        public virtual void MethodSlot3_FireAllNuclearMissiles() { }
    }
    
    class VehicleUser
    {
        public delegate void OpenGasTankMethod(Car car);
    
        public void OpenGasTank(Vehicle vehicle, OpenGasTankMethod method)
        {
            //it's stopping you here from firing all nuclear weapons
            //by mistaking your car's gas tank for the armageddon switch
            method(vehicle); 
        }
    }
    

    当编译器发出虚拟方法调用时,它只是将索引编译到查找表中。如果你可以通过一艘核潜艇,在那里仅仅因为两辆车都是车就需要一辆车,那么你可能会认为你在调用汽车方法(比如打开油箱),而实际上你只是在制造汽车 系列游戏成为现实。

    class Blah
    {
        private List<Action<object>> _handlers = new List<Action<object>>();
    
        public void AddListener<T>(Action<T> handler)
        {
            //graceful type checking code goes in here somewhere
            _handlers.Add(o => handler((T) o));
        }
    
        void RaiseEvent(object eventArgs)
        {
            foreach (var handler in _handlers) handler(eventArgs);
        }
    }
    
        2
  •  1
  •   Lee    8 年前

    你不能这样做,因为这不安全。如果允许,您可以:

    class OtherChild : BaseType { }
    
    CallBackHandler clbk2 = callBackB;
    clbk2(new OtherChild());
    

    并传递 OtherChild ChildType 请注意,以下内容是安全的,可以编译:

    public delegate void CallBackHandler(ChildType p);
    
    CallBackHandler clbk1 = callBackA;
    CallBackHandler clbk2 = callBackB;
    
        3
  •  1
  •   jdphenix    8 年前

    将委托声明为

    public delegate void CallBackHandler(ChildType p)
    

    BaseType NewChildType ? 没有人知道,这就是为什么你不能在这里。