3

C# 有类似 Python 的东西__getattr__吗?

我有一个具有许多属性的类,它们都共享相同的访问器代码。我希望能够完全删除单个访问器,就像在 Python 中一样。

这是我的代码现在的样子:

class Foo
{
    protected bool Get(string name, bool def)
    {
        try {
            return client.Get(name);
        } catch {
            return def;
        }
    }

    public bool Bar
    {
        get { return Get("bar", true); }
        set { client.Set("bar", value); }
    }

    public bool Baz
    {
        get { return Get("baz", false); }
        set { client.Set("baz", value); }
    }
}

这就是我想要的:

class Foo
{
    public bool Get(string name)
    {
        try {
            return client.Get(name);
        } catch {
            // Look-up default value in hash table and return it
        }
    }

    public void Set(string name, object value)
    {
        client.Set(name, value)
    }
}

有没有办法在 C# 中实现这一点而无需Get直接调用?

谢谢,

4

4 回答 4

2

不。虽然 C# 支持反射,但它是只读的(对于加载的程序集)。这意味着您不能更改任何方法、属性或任何其他元数据。虽然你可以创建一个动态属性,但调用它不是很方便——它甚至比使用你的Get方法更糟糕。除了Dictionary<string, object>为您的班级使用 a 和索引器之外,您无能为力。无论如何,如果你有这么多属性,做字典不是更好吗?

Python 不会在“编译时”(或至少在加载时)检查属性是否存在。C# 可以。这是两种语言之间的根本区别。在 Python 中,您可以执行以下操作:

class my_class:
    pass

my_instance = my_class()
my_instance.my_attr = 1
print(my_instance.my_attr)

在 C# 中,您将无法这样做,因为 C# 实际上会my_attr在编译时检查名称是否存在。

于 2009-02-01T03:34:21.333 回答
1

我不确定,但也许 4.0 版的动态特性会帮助你。不过,您将不得不等待...

于 2009-02-01T05:12:14.163 回答
1

我可以问:你为什么不想要个别属性?这是表达与对象关联的数据的惯用 .NET 方式。

就个人而言,假设数据不是稀疏的,我会保留属性并让整体方法使用反射 - 这将使您的编译代码尽可能快:

    protected T Get<T>(string name, T @default)
    {
        var prop = GetType().GetProperty(name);
        if(prop == null) return @default;
        return (T) prop.GetValue(this, null);
    }

当然,如果您不关心定义的属性本身,那么索引器和查找(例如字典)就可以了。您还可以使用 postsharp 做一些事情,将一组属性变成一个属性包——不过,这可能不值得。

If you want the properties available for data-binding and runtime discovery, but can't define them at compile-time, then you would need to look at dynamic type descriptors; either ICustomTypeDescriptor or TypeDescriptionProvider - a fair bit of work, but very versatile (let me know if you want more info).

于 2009-02-01T08:53:06.590 回答
0

这与您在 Python 中使用动态属性名称获得的不同,但您可能会发现它很有用:

using System;
using System.Collections.Generic;

namespace Program
{
    class Program
    {
        static void Main(string[] args)
        {
            MyList<int> list = new MyList<int>();
            // Add a property with setter.
            list["One"] = 1;
            // Add a property with getter which takes default value.
            int two = list["Two", 2];
            Console.WriteLine("One={0}", list["One"]);
            Console.WriteLine("Two={0} / {1}", two, list["Two"]);
            try
            {
                Console.WriteLine("Three={0}", list["Three"]);
            }
            catch
            {
                Console.WriteLine("Three does not exist.");
            }
        }
        class MyList<T>
        {
            Dictionary<string, T> dictionary = new Dictionary<string,T>();

            internal T this[string property, T def]
            {
                get
                {
                    T value;
                    if (!dictionary.TryGetValue(property, out value))
                        dictionary.Add(property, value = def);
                    return value;
                }
            }
            internal T this[string property]
            {
                get
                {
                    return dictionary[property];
                }
                set
                {
                    dictionary[property] = value;
                }
            }
        }
    }
}
于 2009-02-01T03:33:47.387 回答