2009-02-01 2 views
2

Есть ли у C# что-нибудь вроде Python's __getattr__?Вспомогательные блоки в C#?

У меня есть класс со многими свойствами, и все они имеют один и тот же код доступа. Я хотел бы иметь возможность полностью отказаться от отдельных аксессуаров, как в 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 напрямую?

Спасибо,

ответ

2

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

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 существует во время компиляции.

+0

Свойства не *, что * много (около 20), но это повторение кода в любом случае, и мне не нравится его вид. =) Я хочу использовать свойства, а не словарь по той же причине. Свойства выглядят лучше. О, и ключи клиента могут измениться. –

+0

Это невозможно. У C# даже нет универсального #define! – wj32

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; 
       } 
      } 
     } 
    } 
} 
+0

Я не уверен, что понимаю, что вы подразумеваете под TryGet (клиент - это класс библиотеки, поэтому я не могу изменить его поведение), но производительность все равно не очень важна. –

+0

Например, System.Collections.Generic.Dictionary имеет метод TryGetValue, который возвращает true, если ключ уже существует и false в противном случае. Если класс, который вы используете, не имеет такого метода, тогда у вас нет выбора, и хорошо, что производительность не имеет значения. –

+0

ОК, я изменил свой ответ на то, что вы можете найти полезным (не так ли?). Обратите внимание, что индексщик, который принимает значение по умолчанию, использует TryGetValue, чтобы избежать try/catch. –

1

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

+0

Да, они будут. См. Http://msdn.microsoft.com/en-us/library/system.dynamic.dynamicobject%28VS.100%29.aspx – wj32

+0

Хе-хе, с вашим голосованием, у меня теперь есть репутация 1969 года. Какое совпадение, да? –

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, чтобы превратить набор свойств в пакет свойств - вероятно, это не стоит того.

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

+0

I * do * хочу отдельные свойства, я просто не хочу ненужного повторения кода. Как я уже сказал в ответ на ответ Джо Эриксона, производительность не так важна. –

+0

Итак, используя мой подход к размышлению выше - что дублируется? –

Смежные вопросы