C# 具有以子类型为参数的方法的继承类:调用了错误的方法

C# 具有以子类型为参数的方法的继承类:调用了错误的方法,c#,inheritance,unity3d,polymorphism,C#,Inheritance,Unity3d,Polymorphism,我正在做一个纸牌游戏,我有几个控制纸牌行为的脚本 public class BasicCardModel : Draggable { public int hitPoints; public GameObject cardObject; public static string cardName = "Basic Card"; public CardStatus cardStatus = CardStatus.None; public void cop

我正在做一个纸牌游戏,我有几个控制纸牌行为的脚本

public class BasicCardModel : Draggable {
    public int hitPoints;
    public GameObject cardObject;
    public static string cardName = "Basic Card";

    public CardStatus cardStatus = CardStatus.None;

    public void copyAttributes(BasicCardModel bcm) {
        Debug.Log("Calling basic copy attributes");
        hitPoints = bcm.hitPoints;
    }
    ...
}
我有几张类似于以下的专门卡片:

public class AttackCardModel : BasicCardModel {
    public int attackStrength;
    public AttackType attackType;

    public void copyAttributes(AttackCardModel acm) {
        base.copyAttributes(acm);
        attackType = acm.attackType;
        Debug.Log("Attack strength = " + acm.attackStrength);
        attackStrength = acm.attackStrength;
    }
}
我有一个生成这些卡的控制器对象:

public class GameController : MonoBehaviour {
    public GameObject basicCard, attackCard, defenseCard, eventCard, masterCard;
    public GameObject topPlayerDeck, topPlayerHand, topPlayerField;
    public GameObject bottomPlayerDeck, bottomPlayerHand, bottomPlayerField;
    public GameObject eventDeck;
    // Use this for initialization
    void Start () {
        // Link controller to game objects
        topPlayerDeck = GameObject.Find("TopPlayerDeck");
        topPlayerHand = GameObject.Find("TopPlayerHand");
        topPlayerField = GameObject.Find("TopPlayerField");
        bottomPlayerDeck = GameObject.Find("BottomPlayerDeck");
        bottomPlayerHand = GameObject.Find("BottomPlayerHand");
        bottomPlayerField = GameObject.Find("BottomPlayerField");
        eventDeck = GameObject.Find("EventDeck");

        CardCollection cards = generateCards();

        foreach (BasicCardModel card in cards.cards) {
            if(card is AttackCardModel) {
                createCard<AttackCardModel>(topPlayerHand, card as AttackCardModel, Player.Top, CardStatus.Hand);
                createCard<AttackCardModel>(bottomPlayerHand, card as AttackCardModel, Player.Bottom, CardStatus.Hand);
            }
            else if(card is DefenseCardModel) {
                createCard<DefenseCardModel>(topPlayerHand, card as DefenseCardModel, Player.Top, CardStatus.Hand);
                createCard<DefenseCardModel>(bottomPlayerHand, card as DefenseCardModel, Player.Bottom, CardStatus.Hand);
            }
            else {
                createCard<BasicCardModel>(topPlayerHand, card as BasicCardModel, Player.Top, CardStatus.Hand);
                createCard<BasicCardModel>(bottomPlayerHand, card as BasicCardModel, Player.Bottom, CardStatus.Hand);
            }
        }

        /*
        for(int i = 0; i < 2; i++) {
            createCard<AttackCardModel>(topPlayerHand, Player.Top, CardStatus.Hand);
            createCard<AttackCardModel>(bottomPlayerHand, Player.Bottom, CardStatus.Hand);
        }
        for (int i = 0; i < 2; i++) {
            createCard<DefenseCardModel>(topPlayerHand, Player.Top, CardStatus.Hand);
            createCard<DefenseCardModel>(bottomPlayerHand, Player.Bottom, CardStatus.Hand);
        }
        */
    }

    // Update is called once per frame
    void Update () {

    }

    // For testing, have a CardCollection passed in later
    public CardCollection generateCards() {
        CardCollection cards = new CardCollection();
        //AttackCardModel testcard = new AttackCardModel(4, AttackType.SQLInjection, 3);
        cards.cards.Add(new AttackCardModel(4, AttackType.SQLInjection, 3));
        cards.cards.Add(new DefenseCardModel(5, AttackType.SQLInjection, 1));
        //Debug.Log(testcard.attackStrength + "is attack strength");
        return cards;
    }

    public void createCard<T>(GameObject whereToPut, T objectToCopy, Player player, CardStatus cardStatus) where T : BasicCardModel {
        GameObject new_card = Instantiate(basicCard);
        new_card.transform.SetParent(whereToPut.transform, false);
        Destroy(new_card.GetComponent<BasicCardModel>());
        new_card.AddComponent<T>();
        --->new_card.GetComponent<T>().copyAttributes(objectToCopy); <---
        new_card.GetComponent<T>().linkModelToCardObject(new_card);
        new_card.GetComponent<T>().setUpCard<T>(player, cardStatus);
    }
}
公共类游戏控制器:单行为{
公共游戏对象基本卡、攻击卡、防御卡、事件卡、万事达卡;
公共游戏对象TopLayerDeck、TopLayerHand、TopLayerField;
公共游戏对象bottomPlayerDeck、bottomPlayerHand、bottomPlayerField;
公共游戏对象事件组;
//用于初始化
无效开始(){
//将控制器链接到游戏对象
topPlayerDeck=GameObject.Find(“topPlayerDeck”);
topPlayerHand=GameObject.Find(“topPlayerHand”);
topPlayerField=GameObject.Find(“topPlayerField”);
bottomPlayerDeck=GameObject.Find(“bottomPlayerDeck”);
bottomPlayerHand=GameObject.Find(“bottomPlayerHand”);
bottomPlayerField=GameObject.Find(“bottomPlayerField”);
eventDeck=GameObject.Find(“eventDeck”);
卡片收集卡=生成卡片();
foreach(卡中的BasicCardModel卡。卡){
if(卡已被攻击CardModel){
创建卡片(TopLayerHand,卡片作为攻击卡片模型,Player.Top,CardStatus.Hand);
createCard(bottomPlayerHand,卡片为AttackCardModel,Player.Bottom,CardStatus.Hand);
}
否则,如果(卡片为防御性卡片型号){
创建卡片(TopLayerHand,卡片作为防御卡片模型,Player.Top,CardStatus.Hand);
createCard(bottomPlayerHand,卡片作为防御卡片模型,Player.Bottom,CardStatus.Hand);
}
否则{
创建卡片(TopLayerHand,卡片作为基本卡片模型,Player.Top,CardStatus.Hand);
createCard(底部玩家手,作为基本卡片模型的卡片,玩家。底部,卡片状态。手);
}
}
/*
对于(int i=0;i<2;i++){
创建卡片(TopLayerHand,Player.Top,CardStatus.Hand);
createCard(底部玩家手,玩家。底部,卡片状态。手);
}
对于(int i=0;i<2;i++){
创建卡片(TopLayerHand,Player.Top,CardStatus.Hand);
createCard(底部玩家手,玩家。底部,卡片状态。手);
}
*/
}
//每帧调用一次更新
无效更新(){
}
//对于测试,请稍后传入CardCollection
公共卡收集生成卡(){
CardCollection卡=新的CardCollection();
//AttackCardModel testcard=新的AttackCardModel(4,AttackType.SQLInjection,3);
cards.cards.Add(新的AttackCardModel(4,AttackType.SQLInjection,3));
cards.cards.Add(新的防御卡模型(5,AttackType.SQLInjection,1));
//Log(testcard.attackStrength+“是攻击强度”);
回程卡;
}
public void createCard(游戏对象whereToPut,T objectToCopy,玩家,CardStatus CardStatus)其中T:BasicCardModel{
GameObject new_卡=实例化(basicCard);
新建_card.transform.SetParent(whereToPut.transform,false);
销毁(new_card.GetComponent());
新建_card.AddComponent();

--->新建_card.GetComponent().copyAttributes(objectToCopy);使您的
BasicCardModel
copyAttributes
方法虚拟化

public class BasicCardModel : Draggable {
    // ...    
    public virtual void copyAttributes(BasicCardModel bcm) {
        // ...    
    }
    // ...    
}
然后重写它
AttackCardModel
,并在复制其他属性之前将卡模型强制转换为派生类型:

public override void copyAttributes(BasicCardModel bcm) {
    base.copyAttributes(acm);
    var acm = bcm as AttackCardModel;
    if (acm != null) {
        attackType = acm.attackType;
        Debug.Log("Attack strength = " + acm.attackStrength);
        attackStrength = acm.attackStrength;
    }
}

您需要在类型中反映层次结构-一种方法是创建接口,并在
create
方法中为其添加约束:

public interface ICopyableFrom<T>
{
     void CopyAttributes(T src);
}

public void createCard<T>(GameObject whereToPut, T objectToCopy, Player player, CardStatus cardStatus) where T : BasicCardModel, ICopyableFrom<T>
{
        GameObject new_card = Instantiate(basicCard);
        new_card.transform.SetParent(whereToPut.transform, false);
        Destroy(new_card.GetComponent<BasicCardModel>());
        new_card.AddComponent<T>();
        new_card.GetComponent<T>().CopyAttributes(objectToCopy);
        new_card.GetComponent<T>().linkModelToCardObject(new_card);
        new_card.GetComponent<T>().setUpCard<T>(player, cardStatus);
}
公共接口ICopyableFrom
{
无效复制属性(T src);
}
public void createCard(游戏对象whereToPut,T objectToCopy,Player Player,CardStatus CardStatus)其中T:BasicCardModel,ICopyableFrom
{
GameObject new_卡=实例化(basicCard);
新建_card.transform.SetParent(whereToPut.transform,false);
销毁(new_card.GetComponent());
新建_card.AddComponent();
新建_card.GetComponent().CopyAttributes(objectToCopy);
新建卡片.GetComponent().linkModelToCardObject(新卡片);
新建_card.GetComponent().setUpCard(播放器、卡状态);
}
然后您需要在类中实现:

public class AttackCardModel : BasicCardModel, ICopyableFrom<AttackCardModel>
{
    public void CopyAttributes(AttackCardModel src)
    {
    }
}
公共类AttackCardModel:BasicCardModel,ICopyableFrom
{
public void CopyAttributes(AttackCardModel src)
{
}
}

Ah!!这太聪明了。使用
var的原因是什么?还是仅仅为了方便?@ChrisChambers:请注意,这正是我在回答问题时提供的选项之一。我想简化的例子足以回答你的问题。@PeterDuniho-Huh,我想我看得不够仔细。原因是ee这是我自己的错,我需要在我工作的环境中看到它。使用
var
声明局部变量是可选的。在这种情况下,很清楚它必须是什么类型,因为语句在强制转换中详细说明了类型。当您分配方法调用的结果时,乍一看可能不太明显。尽管如此,许多样式指南建议始终使用
var
。如果不确定,IDE应该帮助您检查类型。