C#变量获取器/设置器
本文关键字:设置 获取 变量 | 更新日期: 2023-09-27 18:00:24
我正在尝试为外部程序创建一种简单的方法来获取/设置类中的变量。我有一个类,它有几个变量,比如:
class myClass
{
public int one
{
get{ /* get code here */ }
set{ /* set code here */ }
}
}
我有将近100个变量,而不仅仅是变量"一"。所有的设置方式都与get和set代码相同。我想要的是一种简单的方法来获取和设置变量。示例:不必这样做:
myClass c = new myClass();
c.one = 5;
我想找到一种类似的方法:
myClass c = new myClass();
c.setVariable("variableName", value);
最好让"variableName"文本来自枚举列表,这样它们就可以被引用,比如:
c.setVariable(enumName.varName, value);
我不确定该怎么做,也不确定这是否可能。正如我所说,我有近100个变量需要它们自己的get/set代码,但出于各种原因,我更喜欢只有一个公共get函数和一个公共set函数。
由于我认为反思不是很有效,如果可能的话,我想尽量避免。
我在C#中看到过其他类似的代码:
this["variableName"] = value;
然而,我似乎也找不到让它发挥作用的方法。。。
this["variableName"] = value;
您描述的语法仅对词典有效。如果您不想使用反射,而只想要一个getter和setter,那么您可能应该使用字典编辑:你知道lambda表达式吗?它们是内联匿名方法,通过将它们放在另一个字典中,您可以进行验证!类似这样的东西:
public class MyClass
{
private readonly Dictionary<String, Object> dictionary;
private readonly Dictionary<String, Func<Object, bool>> validators;
public MyClass()
{
this.dictionary = new Dictionary<String, Object>();
this.validators = new Dictionary<String, Func<Object, bool>>();
// Put the default values in the dictionary.
this.dictionary["One"] = 10;
this.dictionary["Another"] = "ABC";
// The validation functions:
this.validators["One"] = obj => ((int)obj) >= 0;
this.validators["Another"] = obj => obj != null;
}
public Object this[string name]
{
get { return this.dictionary[name]; }
set
{
// This assumes the dictionary contains a default for _all_ names.
if (!this.dictionary.Contains(name))
throw new ArgumentException("Name is invalid.");
// Get a validator function. If there is one, it must return true.
Func<Object, bool> validator;
if (validators.TryGetValue(name, out validator) &&
!validator(value))
throw new ArgumentException("Value is invalid.");
// Now set the value.
this.dictionary[name] = value;
}
}
}
关于这个代码需要注意的一些事情:
- dictionary是一个通用对象:dictionary Of String and object,其中
String
是键的类型,Object
是值的类型。如果只有一种值(例如整数),则应将所有Object
更改为int
- 给定一个实例
MyClass myClass
,您可以执行myClass["One"] = 20
来设置One
的值 - 如果您(无意中)尝试使用不存在的名称(
var value = myClass["DoesNotExist"]
)获取值,则会出现异常。您可以将其更改为返回默认值或完全执行其他操作 - 要使用
enum
,请创建枚举并在代码中指定其类型,而不是String
另一种解决方案可以通过这种方式使用反射:
public object this[string name] {
get { return this.GetType().GetProperty(name).GetValue(this, null); }
set { this.GetType().GetProperty(name).SetValue(this, value, null); }
}
或:
public void SetVariable(string name, object value){
this.GetType().GetProperty(name).SetValue(this, value, null);
}
我不会对设计发表评论,但实现起来相当简单。你根本不需要反思,你只需要大量的打字。一般来说,你想要的基本上是这样的:
public class MyClass
{
public enum Variables {
one,
two
}
private int one {
get { /* get; */ }
set { /* set; */ }
}
private int two {
get { /* get; */ }
set { /* set; */ }
}
public object getVariable(Variables v) {
switch(v) {
case Variables.one: return one;
case Variables.two: return two;
default: throw new InvalidArgumentException("v");
}
}
public void setVariable(Variables v, object value) {
switch(v) {
case Variables.one: one = (int)value; return;
case Variables.two: two = (int)value; return;
default: throw new InvalidArgumentException("v");
}
}
}
当然,你没有进行类型检查,所以很多事情都会在你脸上爆炸。使用反射而不造成太大性能压力的另一种方法是静态编译enum->getter和enum->setter方法的字典(不仅是MethodInfo,还有一个委托)。这将导致启动性能受到冲击。但在获取和设置值时,它不会(特别)损害性能。
[编辑]
上述也可以这样实现:
public object this[Variables v]
{
get { return getVariable(v); /* or move implementation here */ }
set { serVariable(v, value); /* or move implementation here */ }
}
这将使您能够编写(例如)myObject[MyClass.Variables.one] = 5
。
[编辑2]
以下各项已测试工作。当面对正常反射(或巨大的转换)时,我对性能一无所知。