Вопрос

Есть ли в 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)
    }
}

Есть ли способ добиться этого на С# без вызова Get напрямую?

Спасибо,

Это было полезно?

Решение

Нет.Хотя C# поддерживает отражение, оно доступно только для чтения (для загруженных сборок).Это означает, что вы не можете изменять какие-либо методы, свойства или любые другие метаданные.Хотя ты мог бы создать динамическое свойство, звонить по нему было бы не очень удобно - это было бы даже хуже, чем пользоваться своим Get метод.Помимо использования Dictionary<string, object> и индексатор для вашего класса, вы больше ничего не можете сделать.В любом случае, не лучше ли создавать словарь, если у вас так много свойств?

Python не проверяет, существует ли атрибут во время компиляции (или, по крайней мере, во время загрузки).С# делает.Это фундаментальное различие между двумя языками.В Python вы можете сделать:

class my_class:
    pass

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

В C# вы не сможете этого сделать, потому что C# фактически проверяет, является ли имя my_attr существует во время компиляции.

Другие советы

Я не уверен, но возможно вам в этом помогут динамические возможности версии 4.0.Хотя придется подождать...

Могу я спросить: почему вам не нужны отдельные свойства?Это идиоматический способ .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, чтобы превратить набор свойств в мешок свойств - хотя, вероятно, оно того не стоит.

Если вы хотите, чтобы свойства были доступны для привязки данных и обнаружения во время выполнения, но не можете определить их во время компиляции, вам нужно будет просмотреть дескрипторы динамических типов;или ICustomTypeDescriptor или TypeDescriptionProvider - работы немного, но очень разносторонне (дайте мне знать, если вам нужна дополнительная информация).

Это не то же самое, что вы получаете в 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;
                }
            }
        }
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top