C#等价于Python属性自定义/Javascript对象文本

本文关键字:Javascript 对象 文本 自定义 等价于 Python 属性 | 更新日期: 2023-09-27 18:28:42

我喜欢Python的一点是可以自定义属性访问的方式:

class Foo(object):
    def __getattr__(self, name):
        if some_predicate(name):
            # ...
        else:
            # Default behaviour
            raise AttributeError

您可以使用Javascript的对象文字表示法更直接地执行类似的操作。

我的问题是:你怎么能在C#中实现类似的东西?正在重载"。"操作员是这样做的一种方式,但它不允许进入。

我脑海中的一个例子是这样定义一个类:

public class MyClass
{
    public IDictionary Properties {get; private set;}
    public MyClass(IDictionary properties)
    {
        this.Properties = properties;
    }
    // Overload the '.' operator - not allowed!
    public static object operator .(MyClass inst, string name)
    {
        return inst.Properties[name];
    }
}

使用这样的类:

class Program
{
    static void Main(string[] args)
    {
        IDictionary properties = new Dictionary<string, string>() {
            { "prop1", "value1"}, { "prop2", "value2"} };
        var my = new MyClass(properties);
        System.Console.WriteLine(my.prop1); // Doesn't work!
    }
}

(注意:我在这里问了一个关于C++的类似问题;最初是同一个问题,但为了更具体地针对每种语言进行了拆分。)

C#等价于Python属性自定义/Javascript对象文本

您有一个内置的对此的支持。您应该从DynamicObject派生类,并通过使用传递给构造函数的字典检查属性是否有效来覆盖它的TryGetMember/TrySetMember

另一种选择是只使用ExpandoObject作为属性包。

然而,虽然您确实获得了动态语言所具有的一定程度的功能,但您却失去了C#的原生特性,如类型安全、编译时检查和IDE代码完成支持。

@galenus给出了我接受的答案,但为了记录在案,我想我应该为更新为使用DynamicObject的示例添加代码。

public class MyClass : DynamicObject
{
    public IDictionary<string, object> Properties { get; private set; }
    public MyClass(IDictionary<string, object> properties)
    {
        this.Properties = properties;
    }
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        return Properties.TryGetValue(binder.Name, out result);
    }
}

class Program
{
    static void Main(string[] args)
    {
        IDictionary<string, object> properties = new Dictionary<string, object>() {
            { "prop1", "value1"}, { "prop2", "value2"} };
        dynamic my = new MyClass(properties);
        System.Console.WriteLine(my.prop1);
    }
}