2

我有一系列“代码”,我想引用我班级中的属性。但是,当我设置字典的值时,属性不会更新。下面的一个例子

public Foo() {
    this.CodeMap = new Dictionary<string, object>();
    this.CodeMap.Add("stat", this.Status);
    this.CodeMap.Add("ver", this.Version);
}

public int Status { get; set; }

public int Version { get; set; }

和调用代码

foo.CodeMap["stat"] = 27;
/* foo.Status is not set to 27 */

有没有办法在.NET 中做到这一点。我相信发生错误是因为字典值不是 ref 值,但我不确定执行此操作的最佳方法。我看到了https://stackoverflow.com/a/10350484/450745但这有点与我想要的相反。

4

5 回答 5

3

对于未来的观众,在简单的情况下使用 Func'<'T'>' 就足够了。

  public string TestProperty {get; set;}
  public Dictionary<int, Func<string>> dictionary;

  Constructor()
  {
    dictionary = new Dictionary<int, Func<string>>
    {
        {1, ()=>TestProperty }
    }
  }

当像这样使用时:

  dictionary[1]() or dictionary[1].Invoke()

它返回当前财产的实际价值。

于 2015-07-02T12:41:41.590 回答
1

我相信发生错误是因为字典值不是 ref 值,

不,是因为你没有设置foo.Statusfoo.CodeMap并且foo.Status是不同的。

如果要同步值,则应手动进行。您可以继承IDictionary<TKey,TValue>并覆盖该Add方法。

void Add(TKey key, TValue value)
{
   if (key is string && key.Equals("stat"))
   {
      this.stat = (int)value;
   }
}
于 2013-01-12T04:25:41.020 回答
1

您的代码不起作用,因为您将键“stat”添加到Dictionary具有赋值时 Status 具有的任何值。当您稍后更新该键的值时,它不会自动更新您的属性。您正在将某个时间点的属性值添加到 中Dictionary,而不是属性本身。

使用标准无法实现您想要做的事情Dictionary。不过,您有几个看起来并不可怕的选择。

可观察字典

请参阅此博客文章和此stackoverflow 线程

总体思路是编写一个继承自IDictionary<TKey, TValue>INotifyCollectionChanged和的类INotifyPropertyChanged

这将为您提供一些挂钩,您可以为其编写事件处理程序,理论上可以让您更新某些属性或您想做的任何其他事情。

重构你的代码

如果您不喜欢上述内容,那么您可以稍微重构您的代码。

考虑一下:

public class Foo
{
    public Dictionary<string, object> CodeMap;

    public int Status
    {
        get 
        {
            int status;
            if (int.TryParse(CodeMap["stat"].ToString(), out status))
            {
                return status;
            }
            else
            {
                throw new Exception("Status has a non-numeric value");
            }
        }
        set 
        { 
            CodeMap["stat"] = value; 
        }
    }

    public Foo()
    {
        CodeMap = new Dictionary<string, object>();
    }
}

然后你可以拨打同样的电话:

Foo foo = new Foo();
foo.CodeMap["stat"] = 27;

Console.WriteLine(foo.Status.ToString());  // prints 27

希望这很明显为什么会这样。现在该属性实际上引用了Dictionary. 请注意,您不能以与以前相同的方式添加初始值,因为KeyNotFoundException当 getter 尝试访问该键时您会得到一个。不过,我认为这是一个很小的缺点。

于 2013-01-12T05:11:12.110 回答
0

字典不会更新先前值属性的值。当您存储foo.CodeMap["stat"] = 27;的较早的值foo.CodeMap["stat"](这是 的值Status)被覆盖27

字典中由键(在您的情况下为“stat”)标识的位置是数据存储,即数据CodeMap["stat"]的存储位置,而不是相反。您存储在此位置的任何内容都会覆盖以前的数据。

您应该详细说明您要解决的实际问题。您的问题不够清楚,读者无法推断出实际的需求/问题。

于 2013-01-12T04:38:22.910 回答
0

另一种方法是使用ExpandoObject。这是一种与字典绑定的示例:

public class Foo
{
    public Foo()
    {
        Properties = new ExpandoObject();
        Status = 0;
        Version = 0;
    }

    public dynamic Properties { get; set; }

    public IDictionary<string, object> CodeMap
    {
        get { return Properties; }
    }

    private int _status;
    public int Status
    {
        get { return _status; }
        set
        {
            _status = value;
            Properties.stat = _status;
        }
    }

    private int _version;
    public int Version
    {
        get { return _version; }
        set
        {
            _version = value;
            Properties.ver = _version;
        }
    }
}

使用:

var foo = new Foo
                {
                    Status = 1,
                    Version = 2
                };

Console.WriteLine(foo.CodeMap["stat"]);
Console.WriteLine(foo.CodeMap["ver"]);
Console.WriteLine(foo.Properties.stat);
Console.WriteLine(foo.Properties.ver);
于 2013-01-12T13:30:18.990 回答