通用协方差解决方法?

Jus*_*les 2 c# generics casting

我有子弹:

public LaserBullets : Projectile
Run Code Online (Sandbox Code Playgroud)

我有一把枪,它继承了一种基本武器,子弹类型与衍生枪一起:

public LaserWeapon : Weapon<LaserBullets>
Run Code Online (Sandbox Code Playgroud)

我有一个属性来建立一个玩家的当前武器:

public Weapon<Projectile> CurrentWeapon
{
    set { currentWeapon = value; }
}
Run Code Online (Sandbox Code Playgroud)

这失败了(不能隐式地转换LaserWeaponWeapon<Projectile>)

player.CurrentWeapon = new LaserWeapon();
Run Code Online (Sandbox Code Playgroud)

我已经读到C#中没有对某些协方差的支持,但我不想认为我被困在这里.有没有办法让我的情况有效?我正在尝试在玩家类中维护一个基础武器,但在另一个类中使用更具体的武器.

我尝试为LaserWeapon创建自己的强制转换操作符,但是我收到了一个关于无法强制转换为基类的错误.

Luk*_*oid 5

我相信你的例子会有效,如果Weapon<T>是一个协变的接口声明如下:

public interface Weapon<out TProjectile>
{
}
Run Code Online (Sandbox Code Playgroud)

这仅适用于TProjectile用作返回值的位置,例如:

TProjectile Fire();
Run Code Online (Sandbox Code Playgroud)

但是在用作输入参数的地方不会起作用TProjectile,例如:

LoadClip(IEnumerable<TProjectile> ammo);
Run Code Online (Sandbox Code Playgroud)

从您的评论中,我可以看到您在通用返回值之后,因此请按如下方式创建一个接口:

public interface IWeapon<out TProjectile> where TProjectile : Projectile
{
    TProjectile Fire();
}
Run Code Online (Sandbox Code Playgroud)

然后使用这个接口实现; 没有什么可以阻止你拥有一个有用的基类,例如

public abstract class Weapon<TProjectile> : IWeapon<TProjectile> where TProjectile : Projectile
{
    public abstract TProjectile Fire();
}
Run Code Online (Sandbox Code Playgroud)

只要您的玩家类别符合以下条件:

public class Player
{
    public IWeapon<Projectile> CurrentWeapon { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

这允许你仍然使用CurrentWeapon.Fire()哪个将返回一个实例Projectile.