没有 return 值和一个允许子类型 类 的参数的函数的 C# 委托(作为参数)
C# delegate for function with no return value and one parameter that allows sub type classes (as parameter)
我正在寻找一个委托,它封装了一个 return 没有值并采用一个参数的方法,就像 Action< T > 那样,但不幸的是那个委托与采用 子类型 作为参数的方法不匹配...
这就是我想要做的:
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)
{
}
}
我了解了协变、逆变等...我知道它涉及继承类型转换,但我对所有这些都有些困惑...
我应该使用哪个委托来使我的代码工作?
你不能这样做,因为它不安全。如果允许的话,你可以这样做:
class OtherChild : BaseType { }
CallBackHandler clbk2 = callBackB;
clbk2(new OtherChild());
并将 OtherChild
的实例传递给需要 ChildType
实例的委托。请注意,以下内容是安全的并且可以编译:
public delegate void CallBackHandler(ChildType p);
CallBackHandler clbk1 = callBackA;
CallBackHandler clbk2 = callBackB;
将委托声明为
public delegate void CallBackHandler(ChildType p)
如果处理程序可以接受并且应该对 BaseType
的实例执行操作,那么如果您传入一个新的 class NewChildType
实例会发生什么情况?没有人知道,这就是你不能来这里的原因。
这是创建强类型来解决的经典类型安全问题。
这是一个例子
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);
}
}
当编译器发出虚方法调用时,它只是将索引编译成查找 table。如果你可以传递一个 NuclearSubmarine ,其中需要 Car 仅仅是因为它们都是 Vehicle,那么你可能认为你正在调用 Car 方法(比如打开你的油箱),而实际上你只是在制作 Fallout系列游戏成为现实。
作为对您评论的回应,这应该可以帮助您入门:
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);
}
}
我正在寻找一个委托,它封装了一个 return 没有值并采用一个参数的方法,就像 Action< T > 那样,但不幸的是那个委托与采用 子类型 作为参数的方法不匹配...
这就是我想要做的:
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)
{
}
}
我了解了协变、逆变等...我知道它涉及继承类型转换,但我对所有这些都有些困惑...
我应该使用哪个委托来使我的代码工作?
你不能这样做,因为它不安全。如果允许的话,你可以这样做:
class OtherChild : BaseType { }
CallBackHandler clbk2 = callBackB;
clbk2(new OtherChild());
并将 OtherChild
的实例传递给需要 ChildType
实例的委托。请注意,以下内容是安全的并且可以编译:
public delegate void CallBackHandler(ChildType p);
CallBackHandler clbk1 = callBackA;
CallBackHandler clbk2 = callBackB;
将委托声明为
public delegate void CallBackHandler(ChildType p)
如果处理程序可以接受并且应该对 BaseType
的实例执行操作,那么如果您传入一个新的 class NewChildType
实例会发生什么情况?没有人知道,这就是你不能来这里的原因。
这是创建强类型来解决的经典类型安全问题。
这是一个例子
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);
}
}
当编译器发出虚方法调用时,它只是将索引编译成查找 table。如果你可以传递一个 NuclearSubmarine ,其中需要 Car 仅仅是因为它们都是 Vehicle,那么你可能认为你正在调用 Car 方法(比如打开你的油箱),而实际上你只是在制作 Fallout系列游戏成为现实。
作为对您评论的回应,这应该可以帮助您入门:
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);
}
}