Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/unity3d/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在方法中强制转换不同的子类_C#_Unity3d_Unet - Fatal编程技术网

C# 在方法中强制转换不同的子类

C# 在方法中强制转换不同的子类,c#,unity3d,unet,C#,Unity3d,Unet,我希望发送、接收和强制转换SkillEvent类的子类,并能够获取其中的自定义参数,具体取决于它的类型 可能有很多不同的子类,它们具有不同的参数 有没有办法避免为每种技能编写不同的方法 class SkillEvent { float timestamp, EventType type } class GrenadeSkillEvent : SkillEvent { Vector3 target_point} [ClientRpc] RpcSendSkillEvent(SkillEvent e

我希望发送、接收和强制转换SkillEvent类的子类,并能够获取其中的自定义参数,具体取决于它的类型

可能有很多不同的子类,它们具有不同的参数

有没有办法避免为每种技能编写不同的方法

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个地方中的每一个,在基类中创建一个抽象方法,然后在每个具体类中重写它。抽象方法创建一个契约,每个具体类都可以用自己的方式来实现

在您的特定示例中,您说希望从不同的具体类中提取不同的参数。您计划如何处理这些参数?是否要创建一个描述对象的字符串?是否要将这些参数传递给您将要进行的服务调用?根据你想要实现的目标来思考。我假设是后一种情况,因为这是实际需要单独参数的情况。所以,让你的