提问者:小点点

使用带有版本开关的get/set定义属性的最有效方法是什么?


我正在编写一个从另一个程序读写内存的程序,但是有两个不同的版本,内存值在一个版本中有偏移,而在第二个版本中没有偏移,因此根据用户选择的设置(v1或v2),我需要确定读/写哪个地址。

现在我的代码如下所示,但我觉得这并不是很有效,而且复制相同的代码会使类变得很长,而实际上它并不需要长。

有没有更有效的方法来完成这一切:

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值


共2个答案

匿名用户

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

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类中(如果希望将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() { }
}

匿名用户

解决这个问题的一种方法是引入一个抽象基类,该基类具有所有属性的具体实现(对于两个版本来说都是相同的),以及针对两个版本之间不同的实现的抽象声明。

例如:

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);
        }
    }
}

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