C# 在方法中强制转换不同的子类
我希望发送、接收和强制转换SkillEvent类的子类,并能够获取其中的自定义参数,具体取决于它的类型 可能有很多不同的子类,它们具有不同的参数 有没有办法避免为每种技能编写不同的方法C# 在方法中强制转换不同的子类,c#,unity3d,unet,C#,Unity3d,Unet,我希望发送、接收和强制转换SkillEvent类的子类,并能够获取其中的自定义参数,具体取决于它的类型 可能有很多不同的子类,它们具有不同的参数 有没有办法避免为每种技能编写不同的方法 class SkillEvent { float timestamp, EventType type } class GrenadeSkillEvent : SkillEvent { Vector3 target_point} [ClientRpc] RpcSendSkillEvent(SkillEvent e
class SkillEvent { float timestamp, EventType type }
class GrenadeSkillEvent : SkillEvent { Vector3 target_point}
[ClientRpc]
RpcSendSkillEvent(SkillEvent event){
eventManager.ExecuteEvent(event);
}
ExecuteEvent(SkillEvent event){
switch(event.type){
case GrenadeSkillEvent :
GrenadeSkillEvent grenadeEvent = (GrenadeSkillEvent) event;
float grenadeParam = event.grenadeParam;
break;
case OtherSkillEvent :
OtherSkillEvent otherEvent = (OtherSkillEvent ) event;
string stringParam = event.stringParam;
break;
}
}
我以为可以这样做,但显然不行
有没有办法避免为每种技能编写不同的方法
class SkillEvent { float timestamp, EventType type }
class GrenadeSkillEvent : SkillEvent { Vector3 target_point}
[ClientRpc]
RpcSendSkillEvent(SkillEvent event){
eventManager.ExecuteEvent(event);
}
ExecuteEvent(SkillEvent event){
switch(event.type){
case GrenadeSkillEvent :
GrenadeSkillEvent grenadeEvent = (GrenadeSkillEvent) event;
float grenadeParam = event.grenadeParam;
break;
case OtherSkillEvent :
OtherSkillEvent otherEvent = (OtherSkillEvent ) event;
string stringParam = event.stringParam;
break;
}
}
编辑:
手榴弹杀手事件和其他SkillEvent是SkillEvent的后代
它们都有一个时间戳和一个类型,我认为需要它来帮助将事件变量转换到正确的SkillEvent子类中
我的问题是它们有相同的方法,比如说execute,但是每种子类都需要不同类型的参数
例如,手榴弹爆炸可能需要一个目标点、爆炸的大小和伤害
BonusEvent可以为玩家增加一些HP
TerraineEvent可以在靠近玩家的重要对象上激活一些自定义动画,等等
这些技能背后的所有逻辑都是相同的
它们都有两种方法:
Simulate(SkillEvent Event) and Render(SkillEvent Event)
但以手榴弹为例,我需要它
Simulate(GrenadeSkillEvent Event) and Render(GrenadeSkillEvent Event)
编辑2:
networkedPlayer.RpcOnSkillEvent(
new SkillEvent[] {
new GrenadeSkillEvent() {
timestamp = state.timestamp,
id = 0,
point = target
}
}
);
var dictionary = new Dictionary<Type, Action<SkillEvent>> {
{
typeof(GrenadeSkillEvent), (SkillEvent e) => {
Debug.Log("GrenadeSkill OnConfirm point"+ ((GrenadeSkillEvent)e).point);
}
}
};
public override void OnConfirm(SkillEvent skillEvent) {
if (skillEvent == null) return;
Debug.Log(skillEvent.GetType());
dictionary[skillEvent.GetType()](skillEvent);
}
void UseGrenade(){ // when some player using grenade skill.
JsonObject json = new JsonObject();
json.addField("id_skill", id); // id of grenade skill
json.addField("timestamp", 1.5f);
json.addField("position", targetPosition);
SendRpcSkill(json.Print()); // converting json to string and sending this string
}
编辑3:
networkedPlayer.RpcOnSkillEvent(
new SkillEvent[] {
new GrenadeSkillEvent() {
timestamp = state.timestamp,
id = 0,
point = target
}
}
);
var dictionary = new Dictionary<Type, Action<SkillEvent>> {
{
typeof(GrenadeSkillEvent), (SkillEvent e) => {
Debug.Log("GrenadeSkill OnConfirm point"+ ((GrenadeSkillEvent)e).point);
}
}
};
public override void OnConfirm(SkillEvent skillEvent) {
if (skillEvent == null) return;
Debug.Log(skillEvent.GetType());
dictionary[skillEvent.GetType()](skillEvent);
}
void UseGrenade(){ // when some player using grenade skill.
JsonObject json = new JsonObject();
json.addField("id_skill", id); // id of grenade skill
json.addField("timestamp", 1.5f);
json.addField("position", targetPosition);
SendRpcSkill(json.Print()); // converting json to string and sending this string
}
var字典=新字典{
{
类型(手榴弹杀手事件),(技能事件e)=>{
Log(“格林纳德斯基尔OnConfirm点”+((格林纳德斯基尔事件)e).point);
}
}
};
确认时的公共覆盖无效(SkillEvent SkillEvent){
if(skillEvent==null)返回;
Log(skillEvent.GetType());
字典[skillEvent.GetType()](skillEvent);
}
如果使用C#7和手榴弹杀手事件
和其他SkillEvent
从SkillEvent
派生,则可以使用模式匹配:
switch (@event) //@event is of SkillEvent type
{
case GrenadeSkillEvent gse:
float grenadeParam = gse.grenadeParam;
break;
case OtherSkillEvent ose:
string stringParam = ose.stringParam;
break;
case null:
//null handling
break;
default:
//other types
break;
}
如果没有,您可以使用字典:
var dictionary = new Dictionary<Type, Action<SkillEvent>>
{
{
typeof(GrenadeSkillEvent), e =>
{
float grenadeParam = ((GrenadeSkillEvent)e).grenadeParam;
//some logic
}
},
{
typeof(OtherSkillEvent), e =>
{
string stringParam = ((OtherSkillEvent)e).stringParam;
//some logic
}
}
}
if (@event == null)
{
//null handling
}
else
{
dictionary[@event.GetType()](@event);
}
var字典=新字典
{
{
类型(格林纳德斯杀手事件),e=>
{
浮动手榴弹底片=((手榴弹杀手事件)e)。手榴弹底片;
//一些逻辑
}
},
{
类型(OtherSkillEvent),e=>
{
字符串stringParam=((OtherSkillEvent)e).stringParam;
//一些逻辑
}
}
}
如果(@event==null)
{
//空处理
}
其他的
{
字典[@event.GetType()](@event);
}
或者,一种更面向对象的方法是在
SkillEvent
内部创建一个抽象方法,并在所有具体类中重写它,但您需要有通用的返回类型和参数。如果您使用C#7和glandeskillevent
和其他SkillEvent
派生自SkillEvent
可以使用模式匹配:
switch (@event) //@event is of SkillEvent type
{
case GrenadeSkillEvent gse:
float grenadeParam = gse.grenadeParam;
break;
case OtherSkillEvent ose:
string stringParam = ose.stringParam;
break;
case null:
//null handling
break;
default:
//other types
break;
}
如果没有,您可以使用字典:
var dictionary = new Dictionary<Type, Action<SkillEvent>>
{
{
typeof(GrenadeSkillEvent), e =>
{
float grenadeParam = ((GrenadeSkillEvent)e).grenadeParam;
//some logic
}
},
{
typeof(OtherSkillEvent), e =>
{
string stringParam = ((OtherSkillEvent)e).stringParam;
//some logic
}
}
}
if (@event == null)
{
//null handling
}
else
{
dictionary[@event.GetType()](@event);
}
var字典=新字典
{
{
类型(格林纳德斯杀手事件),e=>
{
浮动手榴弹底片=((手榴弹杀手事件)e)。手榴弹底片;
//一些逻辑
}
},
{
类型(OtherSkillEvent),e=>
{
字符串stringParam=((OtherSkillEvent)e).stringParam;
//一些逻辑
}
}
}
如果(@event==null)
{
//空处理
}
其他的
{
字典[@event.GetType()](@event);
}
或者,一种更面向对象的方法是在
SkillEvent
中创建一个抽象方法,并在所有具体类中重写它,但需要有通用的返回类型和参数。最好的方法是在顶级类上编写一个通用的getter方法,SkillEvent
然后重写位于的类中的方法是特殊的。由于您似乎需要不同的类型,我认为您可以使用一个方法来执行您在类中参数化的方法
下面是一个示例,显示您当前的代码:
class SkillEvent {
float timestamp;
EventType type ;
public virtual void executeEvent(){ //handles the general case for the execute funciton
execute(timestamp);
}
}
class GrenadeSkillEvent : SkillEvent { //overriden to pass target point into event execution
Vector3 target_point;
public override void executeEvent(){
execute(target_point);
}
}
class BonusEvent : SkillEvent {
int bonus_health;
public override void executeEvent(){/overriden to pass bonus health into event
execute(bonus_health);
}
}
class TerrainEvent : SkillEvent {
GameObject obj;
public override void executeEvent(){//overriden to play animation before event is executed
animation(obj);
execute();
}
}
[ClientRpc]
RpcSendSkillEvent(SkillEvent event){
eventManager.ExecuteEvent(event);
}
ExecuteEvent(SkillEvent event){
event.executeEvent();
}
最好的方法是在顶级类上编写一个通用的getter方法,
SkillEvent
,然后在arespect的类中重写该方法。由于您似乎需要不同的类型,我认为您可以使用一个方法来执行您在类中参数化的方法
下面是一个示例,显示您当前的代码:
class SkillEvent {
float timestamp;
EventType type ;
public virtual void executeEvent(){ //handles the general case for the execute funciton
execute(timestamp);
}
}
class GrenadeSkillEvent : SkillEvent { //overriden to pass target point into event execution
Vector3 target_point;
public override void executeEvent(){
execute(target_point);
}
}
class BonusEvent : SkillEvent {
int bonus_health;
public override void executeEvent(){/overriden to pass bonus health into event
execute(bonus_health);
}
}
class TerrainEvent : SkillEvent {
GameObject obj;
public override void executeEvent(){//overriden to play animation before event is executed
animation(obj);
execute();
}
}
[ClientRpc]
RpcSendSkillEvent(SkillEvent event){
eventManager.ExecuteEvent(event);
}
ExecuteEvent(SkillEvent event){
event.executeEvent();
}
简单的回答是,你可以做你想做的,做你自己的类型,但你真的不想做。这种代码正是多态性设计用来防止的。为了理解为什么,假设您在代码中的5或10个不同位置使用了此模式——每个位置都有一个基于类型的switch语句,并且在每种情况下运行不同的代码。现在让我们假设您有一种新类型的SkillEvent要介绍:您必须查找代码中打开type的每一个地方,并添加更多的代码。所有那些已经被质量保证的代码你突然打开了,所有这些都必须再次被质量保证。另外,如果你忘了其中一个斑点呢?为了添加一个新的类的具体实例,不得不编辑所有这些不同的地方,这是多么痛苦啊
现在考虑这样做的正确方法:对于这10个地方中的每一个,在基类中创建一个抽象方法,然后在每个具体类中重写它。抽象方法创建一个契约,每个具体类都可以用自己的方式来实现
在您的特定示例中,您说希望从不同的具体类中提取不同的参数。您计划如何处理这些参数?是否要创建一个描述对象的字符串?是否要将这些参数传递给您将要进行的服务调用?根据你想要实现的目标来思考。我假设是后一种情况,因为这是实际需要单独参数的情况。所以,让你的