使用 Get/Set 和版本开关定义 属性 的最有效方法是什么?

What is the most efficient way to define a property using Get/Set with a switch for versions?

我正在编写一个程序来从另一个程序读取和写入内存,但是有两个不同的版本并且内存值在一个版本中有偏移量,但在第二个版本中没有,因此取决于用户的设置已选择(v1 或 v2)我需要确定 read/write.

的地址

目前我的代码如下,但我觉得这不是很有效,并且复制相同的代码会使 class 变得很长,而实际上并不需要。

有没有更有效的方法来完成所有这些:

public static int Property
{
    get
    {
        switch (Version)
        {
            case Version.v1:
                return Memory.ReadMemory<int>(0xB7CE50 + 0x2680);
            case Version.v2:
                return Memory.ReadMemory<int>(0xB7CE50);
            default:
                return 0;
        }
    }
    set
    {
        switch (Version)
        {
            case Version.v1:
                Memory.WriteMemory<int>(0xB7CE50 + 0x2680, value);
                break;
            case Version.v2:
                Memory.WriteMemory<int>(0xB7CE50, value);
                break;
            default:
                break;
        }
    }
}

并非所有地址都需要这个偏移量,但大多数地址都需要,所以我也需要考虑到这一点,因此如果 v2

我不能只添加 0x2680 值

解决这个问题的一个明显方法是将关于什么生活在哪里的知识集中到一个中心位置。您可能希望扩展 Version 的定义以包含内存地址(见下文),或者您可能希望将此信息包含在其他 class:

public class Version
{
    public int PropertyAddress { get; init; }

    public static Version Version1 { get; } = new()
    {
        PropertyAddress = 0xB7CE50 + 0x2680,
    };

    public static Version Version2 { get; } = new()
    {
        PropertyAddress = 0xB7CE50,
    };

    private Version() { }
}

(我在这里使用了 C# 9 语法——如果您的目标是较早的语言版本,请进行调整)。

然后您可以将 属性 简化为:

public static int Property
{
    get => Memory.ReadMemory<int>(Version.PropertyAddress);
    set => Memory.WriteMemory<int>(Version.PropertyAddress, value);
}

你也可以,例如将它放在 MemoryAddresses class 中(如果你想将 Version 保留为枚举),然后执行:

private static MemoryAddresses Addresses => Version switch
{
    Version.V1 => MemoryAddresses.V1,
    Version.V2 => MemoryAddresses.V2,
};

public static int Property
{
    get => Memory.ReadMemory<int>(Addresses.PropertyAddress);
    set => Memory.WriteMemory<int>(Addresses.PropertyAddress, value);
}

如果您想利用一个版本中的某些地址是另一个版本中地址的偏移版本这一事实,您可以这样做:

public class Version
{
    public int Offset { get; init; }

    public int Property1Address => 0xB7CE50 + Offset;
    public int Property2Address => 0xB80000 + Offset;
    public int Property3Address { get; init; }

    public static Version Version1 { get; } = new()
    {
        Offset = 0x2680,            // <-- Offset for version 1
        Property3Address = 123456,  // <-- Explicit address for version 1
    };

    public static Version Version2 { get; } = new()
    {
        Offset = 0,                 // <-- No offset for version 2
        Property3Address = 987654,  // <-- Different explicit address for version 2
    };

    private Version() { }
}

解决这个问题的一种方法是引入一个抽象基础 class,它具有两个版本相同的所有属性的具体实现,以及两个版本之间不同实现的抽象声明。

例如:

public abstract class MyBaseClass
{
    public abstract int PropertyThatDiffersByVersion { get; set; }

    public int PropertyThatIsTheSameForBothVersions
    {
        get
        {
            return Memory.ReadMemory<int>(0xB82677); // I made up the address.
        }

        set
        {
            Memory.WriteMemory<int>(0xB82677, value);
        }
    }
}

public sealed class MyVersion1 : MyBaseClass
{
    public override int PropertyThatDiffersByVersion
    {
        get
        {
            return Memory.ReadMemory<int>(0xB7CE50 + 0x2680);
        }

        set
        {
            Memory.WriteMemory<int>(0xB7CE50 + 0x2680, value);
        }
    }
}

public sealed class MyVersion2 : MyBaseClass
{
    public override int PropertyThatDiffersByVersion
    {
        get
        {
            return Memory.ReadMemory<int>(0xB7CE50);
        }

        set
        {
            Memory.WriteMemory<int>(0xB7CE50, value);
        }
    }
}

然后您将创建适当 class(MyVersion1MyVersion2)的实例,并将其传递给接受类型 MyBaseClass 对象的方法。