如何使用类属性填充字典值并随时更新

时间:2019-02-05 15:47:09

标签: c# dictionary properties

我有一些int属性,这些属性会多次更新。我希望字典具有随时更新的值,而不是第一个值的0。

class VolleyballMatchSettlementContext2
    {
        private int _TotalPoints1Set;
        private int _TotalPoints2Set;
        private int _TotalPoints3Set;
        private int _TotalPoints4Set;
        private int _TotalPoints5Set;
        private readonly Dictionary<int, int> _TotalPointCurrentSet;

        public VolleyballMatchSettlementContext2()
        {
            _TotalPointCurrentSet = new Dictionary<int, int>
            {
                {1, _TotalPoints1Set},
                {2, _TotalPoints2Set},
                {3, _TotalPoints3Set},
                {4, _TotalPoints4Set},
                {5, _TotalPoints5Set}
            };
        }
    }

1 个答案:

答案 0 :(得分:0)

如果您不太在意性能。我通过创建一个FieldProxy类来实现此目的,该类使您可以按指定的索引访问字段。代码很大,因为我必须实现整个IDictionary。魔术是通过使用反射来完成的,该反射在性能上并不那么好。

public class FieldProxyDictionary<TK, TV> : IDictionary<TK, TV>
{
    private class FieldProxy<T>
    {
        private readonly Func<T> _getter;
        private readonly Action<T> _setter;

        public FieldProxy(Func<T> getter, Action<T> setter)
        {
            _getter = getter;
            _setter = setter;
        }

        public void Set(T value) => _setter(value);
        public static implicit operator T(FieldProxy<T> proxy) => proxy._getter();
    }

    private readonly Dictionary<TK, FieldProxy<TV>> _dictionary = new Dictionary<TK, FieldProxy<TV>>();

    public TV this[TK index] {
        get => _dictionary[index];
        set => _dictionary[index].Set(value);
    }

    public ICollection<TK> Keys => _dictionary.Keys;

    public ICollection<TV> Values => _dictionary.Values.Cast<TV>().ToArray();

    public int Count => _dictionary.Count;

    public bool IsReadOnly => false;

    [Obsolete("Adding items to " + nameof(FieldProxyDictionary<TK, TV>) + " is not supported. Use " + nameof(AddField) + " insted.")]
    public void Add(TK key, TV value) => throw new NotSupportedException($"Adding items to {nameof(FieldProxyDictionary<TK, TV>)} is not supported. Use {nameof(AddField)} insted.");

    [Obsolete("Adding items to " + nameof(FieldProxyDictionary<TK, TV>) + " is not supported. Use " + nameof(AddField) + " insted.")]
    public void Add(KeyValuePair<TK, TV> item) => throw new NotSupportedException($"Adding items to {nameof(FieldProxyDictionary<TK, TV>)} is not supported. Use {nameof(AddField)} insted.");


    public void AddField(TK index, object instance, string fieldName)
    {
        var field = instance.GetType().GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
        TV getter() => (TV)field.GetValue(instance);
        void setter(TV value) => field.SetValue(instance, value);
        _dictionary[index] = new FieldProxy<TV>(getter, setter);
    }

    public void Clear() => _dictionary.Clear();

    public bool Contains(KeyValuePair<TK, TV> item) => _dictionary.TryGetValue(item.Key, out var value) && ((TV)value).Equals(item.Value);

    public bool ContainsKey(TK key) => _dictionary.ContainsKey(key);

    public void CopyTo(KeyValuePair<TK, TV>[] array, int arrayIndex) =>
        ((ICollection<KeyValuePair<TK, FieldProxy<TV>>>)_dictionary)
        .Select(proxy => new KeyValuePair<TK, TV>(proxy.Key, proxy.Value))
        .ToArray()
        .CopyTo(array, arrayIndex);

    public IEnumerator<KeyValuePair<TK, TV>> GetEnumerator() => _dictionary.Select(proxy => new KeyValuePair<TK, TV>(proxy.Key, proxy.Value)).GetEnumerator();

    public bool Remove(TK key) => _dictionary.Remove(key);

    public bool Remove(KeyValuePair<TK, TV> item) => _dictionary.TryGetValue(item.Key, out var value) && ((TV)value).Equals(item.Value) && _dictionary.Remove(item.Key);

    public bool TryGetValue(TK key, out TV value)
    {
        if (_dictionary.TryGetValue(key, out var proxy))
        {
            value = proxy;
            return true;
        }
        value = default(TV);
        return false;
    }

    IEnumerator IEnumerable.GetEnumerator() => _dictionary.Select(proxy => new KeyValuePair<TK, TV>(proxy.Key, proxy.Value)).GetEnumerator();


}

class VolleyballMatchSettlementContext
{
    private int _TotalPoints1Set;
    private int _TotalPoints2Set;
    private int _TotalPoints3Set;
    private int _TotalPoints4Set;
    private int _TotalPoints5Set;
    public readonly FieldProxyDictionary<int, int> TotalPointCurrentSet;

    public VolleyballMatchSettlementContext()
    {
        TotalPointCurrentSet = new FieldProxyDictionary<int, int>();
        TotalPointCurrentSet.AddField(1, this, nameof(_TotalPoints1Set));
        TotalPointCurrentSet.AddField(2, this, nameof(_TotalPoints2Set));
        TotalPointCurrentSet.AddField(3, this, nameof(_TotalPoints3Set));
        TotalPointCurrentSet.AddField(4, this, nameof(_TotalPoints4Set));
        TotalPointCurrentSet.AddField(5, this, nameof(_TotalPoints5Set));
    }
}

用法是这样的。如果在调试器中检查它,则可以看到这些值存储在上下文实例的字段中。

static class Program
{
    static void Main(string[] _)
    {
        var context = new VolleyballMatchSettlementContext();
        context[1] = 1;
        context[2] = 2;
        context[3] = 3;
        context[4] = 4;
        context[5] = 5;

        Console.WriteLine($"TotalPoints3Set: {context[3]}");
        foreach (var field in context.TotalPointCurrentSet)
        {
            Console.WriteLine($"{field.Key}: {field.Value}");
        }

    }
}