JavaScript中有`动态属性`,难道我`c#`没有?

214 阅读1分钟

前言

最近学习c#的时候,发现一个非常神奇的语法----dictionary["key"],例如拿Dictionary可以这么拿:

var dictionary = new Dictionary<string,string>();
dictionary.Add("test","test");
Console.WriteLine(dictionary["test"]);

说实话很像javascirptobj['key']语法。但是如果在c#中你想这么访问对象属性是不行的:

image.png

但是实际上这只是在Dictionary中加入了Dictionary<TKey,TValue>.Item[TKey] 属性实现的:

image.png so,我们能否使用这个方式实现obj["key"]的形式来访问属性呢?

实现

首先我们根据Dictionary的源码来抄一个Item属性

class TestItem
{
    public string? a { get; set; }

    public object this[object key]
    {
        get
        {
            return "a";
        }
    }
}

这里我们用object来代替泛型来实现一个类似的Item属性,然后我们直接访问一下

image.png

image.png

可以发现顺利的输出了a,到现在为止,我们简单的为对象实现了一个obj["key"]语法。接下来就是为get关联到对象正确的属性上,这里比较简单,我们直接使用反射取值的方式:

class TestItem
{
    public string? a { get; set; }

    public object? this[string key]
    {
        get
        {
            var type = this.GetType();
            var propertyInfo = type.GetProperty(key);
            var value = propertyInfo?.GetValue(this);
            return value;
        }
    }
}

再测试一遍

image.png

image.png

可以看到已经可以使用了。 当然,我们还得实现一个set

class TestItem
{
    public string? a { get; set; }

    public object? this[string key]
    {
        get
        {
            var type = this.GetType();
            var propertyInfo = type.GetProperty(key);
            var value = propertyInfo?.GetValue(this);
            return value;
        }
        set
        {
            var type = this.GetType();
            var propertyInfo = type.GetProperty(key);
            propertyInfo?.SetValue(this, value);
        }
    }
}

再来测试一下

image.png

image.png

可以发现运行成功了,当然我们可以把它抽象成一个抽象类,来方便使用:

abstract class ItemStatement
{
    public virtual object? this[string key]
    {
        get
        {
            var type = this.GetType();
            var propertyInfo = type.GetProperty(key);
            var value = propertyInfo?.GetValue(this);
            return value;
        }
        set
        {
            var type = this.GetType();
            var propertyInfo = type.GetProperty(key);
            propertyInfo?.SetValue(this, value);
        }
    }
}