C#Variable Getters / Setters

时间:2013-02-22 01:14:45

标签: c#

我正在尝试为外部程序创建一种简单的方法来获取/设置我的类中的变量。我所拥有的是一个包含多个变量的类,例如:

class myClass
{
    public int one
    {
        get{ /* get code here */ }
        set{ /* set code here */ }
    }
}

而不仅仅是变量'one',我有接近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函数和一个public set函数。

由于我认为反思不是很有效,我想尽可能避免反复。

我在C#中看到过其他类似的代码:

this["variableName"] = value;

然而我似乎找不到让这项工作成为现实的方法......

3 个答案:

答案 0 :(得分:7)

this["variableName"] = value;

您描述的语法仅对字典有效。如果你不想使用反射,只想要一个getter和setter,你应该使用字典。 修改:您知道lambda expressions吗?它们是内联匿名方法,通过将它们放在另一个字典中,您可以进行验证!像这样:

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

有关此代码的一些注意事项:

  • 字典是一个通用对象:字符串和对象字典,其中String是键的类型,Object是值的类型。如果您只有一种值(例如整数),那么您应该将Object更改为int
  • 根据实例MyClass myClass,您可以myClass["One"] = 20设置One的值。
  • 如果您(无意中)尝试使用不存在的名称(var value = myClass["DoesNotExist"])获取值,您将获得异常。您可以更改此设置以返回默认值或完全执行其他操作。
  • 要使用enum,请创建枚举并在代码中指定其类型而不是String

答案 1 :(得分:1)

另一种解决方案可能是以这种方式使用反射:

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

答案 2 :(得分:0)

我不会对设计发表评论,但实施起来相当简单。您根本不需要反射,只需要进行大量的输入。一般来说,你想要的基本上是这样的:

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-&gt; setter方法的字典(不仅仅是MethodInfo,而是委托)。这将导致启动性能受到打击。但是在获取和设置值时,它不会(afaik)损坏性能(显着)。

<强> [编辑]
以上也可以这样实现:

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]
following已经过测试工作。我不知道在遇到正常反射时的表现(或者说是大转换)。