Skip to main content
 首页 » 编程设计

c#之使用 'params' 关键字来包含单个值以及值集合

2024年04月17日35linjiqin

我知道问题的标题不是很清楚,但让我尽量解释一下。

我正在开发一个修改文件字节的应用程序。为此,我有两个类:Mod 和 Action。

Action 存储在 Mod 的实例中,这告诉应用程序在哪个特定地址修改哪些字节:

public class Action 
{ 
    public Action(int address, params byte[] bytes) 
    { 
        Address = address; 
        Bytes = bytes; 
    } 
 
    public int Address { get; } 
    public byte[] Bytes { get; } 
} 
public class Mod 
{ 
    public Mod(string name, List<Action> actions) 
    { 
        Name = name; 
        Actions = actions; 
    } 
 
    public string Name { get; } 
    public List<Action> Actions { get; } 
} 

现在,我想写一些字节,它们变得相当重复,所以在创建 Action 实例时,我没有将它们分配给 bytes,而是将所述字节数组存储在名为 OpCodes 的静态类中:

public static class OpCodes 
{ 
    public static byte[] BX_LR = {0x70, 0x47}; 
} 

所以现在我想要实现的是:

new Action(0x1AF0F0, 0x01, 0x20, OpCodes.BX_LR) //Return 1. (true) 

如您所见,我想使用字节 0x01、0x20 然后我还想使用 BX_LR 的值,但是,编译器不喜欢这样。

我明白了:

Argument 4: cannot convert from 'byte[]' to 'byte'

我怎样才能做到这一点?

请您参考如下方法:

我在 LinqPad 中想到了这个:

void Main() 
{ 
    var x = new Action(0x1AF0F0, 0x01, 0x20, OpCode.BX_LR); //Return 1. (true) 
    Console.WriteLine(x); 
} 
 
public class Action 
{ 
    public Action(int address, params OpCode[] bytes) 
    { 
        Address = address; 
        Bytes = OpCode.Flatten(bytes); 
    } 
 
    public int Address { get; set; } 
    public byte[] Bytes { get; set; } 
} 
 
public class Mod 
{ 
    public Mod(string name, List<Action> actions) 
    { 
        Name = name; 
        Actions = actions; 
    } 
 
    public string Name { get; set; } 
    public List<Action> Actions { get; set; } 
} 
 
public class OpCode 
{ 
    private byte[] _value; 
 
    private OpCode(byte[] value) 
    { 
        _value = value; 
    } 
 
    public static byte[] BX_LR = {0x70, 0x47}; 
 
    public static implicit operator OpCode (byte value) 
    { 
        return new OpCode(new []{value}); 
    } 
 
    public static implicit operator OpCode (byte[] value) 
    { 
        return new OpCode(value); 
    } 
 
    public static byte[] Flatten (OpCode[] opCodes) 
    { 
        var result = new List<byte>(opCodes.Length); 
        foreach (var opCode in opCodes) 
        { 
            result.AddRange(opCode._value); 
        } 
        return result.ToArray(); 
    } 
} 

LinqPad中的输出如下:

Address 
1765616  
Bytes 
01 20 70 47  

代码使用 OpCode 类(我将 OpCodes 重命名为单数)作为 byte[] 和 byte< 之间的中介。这有助于很好的调用。

Action 的构造函数采用 OpCode 的 params 和任何 byte 或 byte[] 将隐式转换为 OpCode 因此您可以将字节放入调用中...然后在构造中您可以将结构扁平化为单个 byte[ ] 使用专用调用。

注意:由于 LinqPad 的提示,我将 set; 添加到属性中。


这样做的好处在于调用的可读性,但正如您所看到的那样存在开销......该开销仅对长字节序列有意义。

顺便说一句。您可以将 _value 设置为只读,我还建议将 OpCode sealed 设置为 struct。原因是使用代码中显示的 OpCode 将创建一堆短暂的对象,但如果它们是 struct 那么它们将不会加载垃圾收集器。此外,不允许派生类型。编辑:该结构的缺点是您无法控制默认构造函数,这将使用 _values 将其初始化为 null。

另一个建议是将公共(public)静态字段定义为readonly(不允许替换它们)和OpCode,这将节省转换并防止篡改数组。