【问题标题】:C# Inheritance containing another inheritable object?C# 继承包含另一个可继承对象?
【发布时间】:2015-11-14 17:50:00
【问题描述】:

我有以下物品

class Magazine 
{ 
    String intendedGunId {get;}//Returns some Gun.weaponID;
    int size {get;}
    //Implementation
}

class Gun 
{
    public enum FireModes
    {
        Bolt,
        Semi,
        FullAuto
    }

    public FireModes fireMode { get; private set; }

    Magazine magazine;

    public Magazine reload(Magazine newMag)
    {
        if (magazine.intendedGunId == newMag.intendedGunID)
        {
            Magazine temp = magazine;
            this.magazine = newMag;
            return temp;
        }

         return newMag;
    }

    //Other implementation
 }

class AKMag : Mag
{
   //Implementation
}

class AK : Gun
{
   //Implementation
}

我正在设计一把枪和一个弹匣,该枪应始终用于多种不同的枪。

我不认为将 Magazine 变量保留为 T : Magazine 而不仅仅是 Magazine 是一个聪明的主意,因为在重新加载时,几乎任何杂志都可以被接受,而且它感觉不像是安全代码;我觉得黑客很容易利用这一点。

我尝试了以下通用方法:

class Gun<T> where T : Magazine
{
    T magazine;
    //Other implementation
}

class AK : Gun<AKMag>
{

}

问题是一旦我使用泛型,就无法存储Gun&lt;Magazine&gt; 变量,因为在某些时候,编译器会说“无法从Gun&lt;AKMag&gt; 转换为Gun&lt;T&gt; where T : Magazine

基本上,每把枪都有自己的弹匣,只属于它的枪。我正在努力正确地实现这一点,可能是因为对 C# 泛型或 C# 继承缺乏了解。

编辑: 使用枪通用,以下情况不起作用:

Gun<Magazine> someGun;

public void func (Gun<Magazine> gun)
{
    this.someGun = gun;
}

//In another class

AK<AKMagazine> someAK;

public void func2 ()
{
    func1 (someAK);  //Error: "Can not convert from `Gun<AKMag>` to `Gun<T> where T : Magazine`."
}

编辑:我认为最好的方法是检查magazine.GetType() == newMag.GetType() 每当杂志要改变时,界面也可以工作。

【问题讨论】:

  • 分享让编译器抱怨的代码。我不明白你的确切意思。
  • 创建一个IGun 接口,在Gun&lt;T&gt; 中实现它,并将你的枪存储在类型为IGun 的变量中。
  • @MarcinJuraszek,我可以问你更多细节吗?我想我明白了,但我不确定我会怎么做。因为我不确定接口是否可以工作,所以我会向 Gun 类添加更多信息。
  • 也许它有助于使 T 协变 - 请参阅 stackoverflow.com/questions/10956993/out-t-vs-t-in-generics
  • @Ruud,虽然这似乎可行,但它需要一个接口。我将不得不尝试转换它。

标签: c# inheritance


【解决方案1】:

只使用普通的旧接口怎么样?

    class Program
    {
        static void Main(string[] args)
        {
            Gun myGun = new AK();
            Console.WriteLine(myGun.load(new AK_Mag())); // true
            Console.WriteLine(myGun.load(new ShotGun_Mag())); // false
            func2();
        }

        static Gun someGun;
        static void func1(Gun gun)
        {
            someGun = gun; 
        }

        public static void func2()
        {
            Gun someAK = new AK();
            someAK.load(new AK_Mag());
            func1(someAK);
        }
    }

    public class AK : Gun
    {
        public bool load(Mag mag)
        {
            if (mag == null)
                return false;
            if ( mag.GetType() != typeof(AK_Mag))
            {
                return false;
            }

            return true;
        }

        public void shoot(int x, int y, int z)
        {
            throw new NotImplementedException();
        }

        public bool setFireMode(Gun.FireMode mode)
        {
            this.mode = mode;
            return true;
        }
    }

    public class AK_Mag : Mag
    {
        public int Remain()
        {
            throw new NotImplementedException();
        }
    }

    public class ShotGun_Mag : Mag
    {
        public int Remain()
        {
            throw new NotImplementedException();
        }
    }

    public interface Gun
    {
        public enum FireMode { Manual, Burst };
        bool load(Mag mag);
        void shoot(int x, int y, int z);
        bool setFireMode(FireMode mode);        
    }

    public interface Mag
    {
        int Remain();
    }

【讨论】:

  • 我可以试一试,但接下来我必须处理 FireMode 枚举的放置位置。
  • 我的意见是将该枚举放入您实施的枪类中。
  • interface Gun 设为通用并且不再需要mag.GetType() != typeof(AK_Mag) 检查。
  • @TLJ,但是枚举存在于所有枪支中。
【解决方案2】:

泛型类型参数的继承不涉及泛型类的继承。我认为泛型在这里不是正确的解决方案。

试试这个方法:

class Magazine
{
    public readonly Type GunType; // Used for identification of compatible gun type.

    public Magazine (Type gunType)
    {
        this.GunType = gunType;
    }
}

class Gun
{
    // Factory method
    public Magazine CreateMagazine()
    {
        return new Magazine(this.GetType());
    }

    public Magazine Reload(Magazine newMag)
    {
        // Test whether the magazine is compatible with the current gun.
        if (newMag.GunType != this.GetType()) {
            throw new ArgumentException();
            // Or just reject the new magazine and keep the current one.
        }

        // Your reload logic goes here ...
    }
}

泛型的问题在于T&lt;A&gt;T&lt;B&gt; 这两种类型不兼容赋值,即使AB 之间存在继承关系。另一个问题是,泛型在编译时就完全解决了。您需要一种更动态的方法。在游戏中,您可能希望在用户的库存中存储枪支和弹匣,并以相同的方式处理所有枪支和弹匣类型。将所需类型存储为 System.Type 可以在运行时以完全动态的方式完成。

您会创建和使用这样的杂志:

Gun gun = new AK();
Magazine magazine = gun.CreateMagazine();
Magazine other = gun.Reload(magazine);

【讨论】:

  • 我现在测试一下,然后告诉你。乍一看还不错!
  • 编译器现在告诉我 AKMag 是一种类型,但不是,这在给定的上下文中无效。
  • 请解释您的错误信息。请注意,this.GetType() 返回一个类型为 System.Type 的类,它描述了枪类。它本身不是枪类。
猜你喜欢
  • 1970-01-01
  • 2013-01-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-19
  • 1970-01-01
相关资源
最近更新 更多