存储在数组中时,C#字段不保留值

时间:2014-09-11 08:02:19

标签: c# arrays string

我的程序中有一个情况,我有大约20个字段。所有这些都是字符串。现在我还有一个大小为20的字符串数组。我想从存储在该数组中的字符串中依次初始化这些字段。我不想这样做:

field1 = array [0];

field2 = array [1];

...

field20 = array [19];

所以我写了一个这样的测试程序,但它不能用于字符串。它只适用于引用类型。有没有办法做到这一点?

public class Program
{
    private string name;
    private string id;

    private void Func()
    {
        var array = new[] {name, id};
        for (int i = 0; i < array.Length; i++)
        {
            array[i] = "some string";
        }
    }

    public static void Main(string[] args)
    {
        var p = new Program();
        p.Func();
        Console.WriteLine(p.name); // prints null
    }
}

2 个答案:

答案 0 :(得分:3)

关于行为的假设是不正确的。

// Create a NEW array with the specified expressions which are evaluated
// immediately (to the current values of the fields)..
var array = new[] {name, id};

// Meaning it is equivalent to this .. note that the field names have
// NOTHING to do with the array object itself.
var array = new[] {(string)null, (string)null};

// Then for each item in the array, assign it a value
// (replacing what was already there anyway)
for (int i = 0; i < array.Length; i++) {
    array[i] = "some string";
}

最后我们得到一个看起来像["some string", "some string"]的数组。同样,字段没有“连接”。这个问题与引用类型无关(而且字符串也是引用类型)。

最好的(通常是正确的)方式是诚实地以不同的方式做到这一点。虽然可以包装字段访问/设置器并且始终存在反射..如果真正需要动态名称,则应该使用字典或类似字典


这是一种使用代理来包装赋值操作的方法。此示例使用操作和"Statement Lambda" syntax

var setters = new Dictionary<string, Action<Program, string>>() {
    { "name", (p, value) => p.name = value },
    { "id", (p, value) => p.id = value },
};

// For each field setter, assign a value (could use the name as a look-up)
foreach (var setter in setters.Values) {
    setter(this, "some string");
}

这是有效的,因为setter(..)会调用之前定义的实际分配给相应成员的操作。使用这样的查找/代理(使用动作,函数或更复杂的类型)对于某些情况是一种有效的方法,但在不需要时应该避免使用。


也可以Reflection完成。

var t = this.GetType();
var fieldNames = new [] { "name", "id" };
var bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance;
foreach (var name in fieldNames) {
   var fieldInfo = t.GetField(name, bindingFlags);
   fieldInfo.SetValue(this, "some string");
}

反思通常应该是“最后的手段”。它会丢失静态类型信息,将许多错误推迟到运行时,并且会带来性能损失(授予,可能无关紧要)。有一些非常漂亮的东西可以做(特别是当表达和注释也被使用时)..但反射是最好的魔法,直到真正需要它。

答案 1 :(得分:2)

看看这是否是你想要实现的目标:

public class Program
{
    private string name;
    private string id;
    private Dictionary<string, int> mapper = new Dictionary<string, int>();
    private String[] array= null;
    public Program()
    {
        mapper.Add("name", 1);
        mapper.Add("id", 2);
    }


    public string Name
    {
        get { return array[mapper["name"]]; }
    }

    public string Id
    {
        get { return array[mapper["id"]]; }
    }

    private void Func()
    {
        array = new[] { name, id };

        for (int i = 0; i < array.Length; i++)
        {
            array[i] = "some string";
        }
    }

    public static void Main(string[] args)
    {
        var p = new Program();
        p.Func();
        Console.WriteLine(p.name); // prints null
    }
}