我正在try 为游戏制作一个基本的"拼写系统",并试图想出一种以模块化方式实现"拼写行为"的好方法.我有一个小问题,我希望某些方法只能由某些"类型"的咒语使用.代码示例:

public abstract class Spell 
{
    public abstract void DoStuff();

    public void DoProjectileMovement() 
    {
        //Handle moving spell
        //Want to only allow calling from spells which implement "Projectile" interface
    }
}

public interface Projectile 
{
    int projNum { get; set; }
    float projSpeed { get; set; }
}

public class Fireball : Spell, Projectile 
{
    public int projNum { get; set; }
    public float projSpeed { get; set; }

    public override void DoStuff()
    {
        DoProjectileMovement();
    }
}

就目前而言,DoProject tileMovement()方法无法使用Project界面中的属性,而我希望它能够访问该界面.显而易见的选项似乎只是将其作为参数传递:

public void DoProjectileMovement(Projectile proj) 
{
    //Handle moving spell
    //Now it can access projectile properties through proj
}

但是当在Fireball中调用这个方法时,我必须这样做:

public override void DoStuff()
{
    DoProjectileMovement(this);
}

拥有额外的this感觉多余.我知道投射接口永远不会由除Spell之外的任何其他Base实现.如果它是由Spell实现的,我希望能够调用DoProjectileMovement().另一种方法是让DoProject tileMovement方法在Project界面中具有默认实现,并以某种方式指定Project tile也保证是一个拼写.这可能吗?

此外,拥有一个单独的抽象类"Project Spell"的方法不起作用,因为我希望能够同时使用多个不同的接口.(例如,Fireball也可能是"Exploding",那么我就不能同时从两个抽象类"OutlotileSpell"和"ExplodingSpell"继承).

推荐答案

我想到了一些可能性.

选项1:使用扩展方法

public abstract class Spell
{
    public abstract void DoStuff();
}

public static class ProjectileExtensions
{
    public static void DoProjectileMovement<TSpell>(this TSpell projectile)
        where TSpell : Spell, Projectile
    {
        // Handle moving spell
        // (You can access members of Spell and Projectile here)
    }
}

public class Fireball : Spell, Projectile
{
    public int projNum { get; set; }
    public float projSpeed { get; set; }

    public override void DoStuff()
    {
        this.DoProjectileMovement(); // 'this' qualifier is required
    }
}

您甚至可以编写需要实现接口组合的扩展方法.

public static class ProjectileExtensions
{
    public static void DoExplodingProjectileMovement<TSpell>(this TSpell projectile)
        where TSpell : Spell, Exploding, Projectile
    {
        // Handle explosive moving spell
        // (You can access members of Spell, Exploding, and Projectile here)
    }
}

选项2:使用默认接口实现(仅限.NET Core)

此选项要求您引入由Spell和Outlittile实现的ISpell界面.

public interface ISpell
{
    void DoStuff();
}

public abstract class Spell : ISpell
{
    public abstract void DoStuff();
}

public interface Projectile : ISpell
{
    int projNum { get; set; }
    float projSpeed { get; set; }

    void DoProjectileMovement()
    {
        // Handle moving spell
        // (You can access members of ISpell and Projectile here)
    }
}

public class Fireball : Spell, Projectile
{
    public int projNum { get; set; }
    public float projSpeed { get; set; }

    public override void DoStuff()
    {
        ((Projectile)this).DoProjectileMovement(); // cast is required
    }
}

选项3:重构以使用组合而不是继承

将投影仪从接口更改为类.

public class Projectile
{
    private Spell Spell { get; }

    public Projectile(Spell spell)
    {
        Spell = spell;
    }

    public int projNum { get; set; }
    public float projSpeed { get; set; }

    public void DoProjectileMovement()
    {
        // Handle moving spell
        // (You can access members of Spell (via the Spell property) and Projectile here)
    }
}

public class Fireball : Spell
{
    private Projectile Projectile { get; }

    public Fireball()
    {
        Projectile = new Projectile(this);
    }

    public int projNum { get; set; }
    public float projSpeed { get; set; }

    public override void DoStuff()
    {
        Projectile.DoProjectileMovement();
    }
}

Csharp相关问答推荐

从C#网站调用时找不到存储过程

EF Core:看不到任何查询日志(log)?

CsWin32如何创建PWSTR的实例,例如GetWindowText

选取器与.NET Maui MVVM的绑定属性

内部接口和类的DI解析

WeakReference未被垃圾收集

尽管保证密钥不同,但已添加相同密钥的项(&Q;)

Cosmos SDK和Newtonsoft对静态只读记录的可能Mutations

如何在NET 8最小API中自动记录TypedResults.Stream响应

如何在C#中创建VS代码中的控制台应用程序时自动生成Main方法

在C#中过滤Excel文件

无法使用[FromForm]发送带有图像和JSON的多部分请求

在ASP.NET Core 8 MVC中本地化共享视图

.NET 8在appsettings.json中核心使用词典URI、URI&>

Azure函数-在外部启动类中生成配置时出错

如何将%{v_扩展}转换为%{v_扩展}>>

RCL在毛伊岛应用程序和Blazor服务器应用程序.Net 8.0中使用页面

使用C#12中的主构造函数进行空判断

使用C#代码和SQL SERVER中的相同证书签名会产生不同的结果

.NET文档对继承的困惑