свойства 'кэширования' - PullRequest
1 голос
/ 10 августа 2010

У меня есть класс, заполненный свойствами.Когда к свойствам обращаются, он считывает некоторые значения из XDocument.

public class Foo
{
 private XDocument root;

 public Foo(Stream str)
 {
  root = XDocument.load(str);
 }

 public String Bar
 {
  get
  {
   return root.Element("bar").Value;
  }
 }

}

Только кажется, что это немного накладные расходы, поскольку каждый раз, когда к нему обращаются, ему приходится снова читать XDocument.Я попытался немного «кешировать» это следующим образом:

public String Bar
{
 get
 {
  if(String.IsNullOrEmpty(this.Bar))
   return root.Element("bar").Value;
  else
   return this.Bar;
 }
}

Мне это кажется довольно приличным, только у меня есть одна проблема с этим.Класс имеет около 200 свойств.Каждый раз, когда мне приходится делать эту проверку, и, поскольку ООП - это не копирование больших частей кода, есть ли способ заставить эту работу работать автоматически?

Ответы [ 4 ]

4 голосов
/ 10 августа 2010

Как упоминалось "thelost", не имейте отдельного поля для каждого свойства. Храните словарь в качестве кэша, чтобы ничего не платить за свойства, к которым вы не обращались.

Я бы предложил вам метод, который вы можете предоставить с механизмом получения реального значения. Например:

public class Foo
{
    private enum CacheKey
    {
        Bar, Baz, ...;
    }

    private readonly XDocument doc;
    private readonly Dictionary<CacheKey, string> cache;

    private string Fetch(CacheKey key, Func<XDocument, string> computation)
    {
        string result;
        if (!cache.TryGetValue(key, out result))
        {
            result = computation(doc);
            cache[key] = result;
        }
        return result;
    }

    public string Bar
    {
        get { return Fetch(CacheKey.Bar, doc => doc.Element("bar").Value); }
    }
}

Таким образом, каждое свойство оказывается достаточно компактным - оно в основном выражает ключ кеша и способ вычисления свойства. Если вам нужны свойства разных типов, вы можете захотеть, чтобы в кеше было просто TValue как object, и сделать метод Fetch универсальным, приводя при необходимости Это приведет к тому, что типы значений в боксе, по общему признанию.

Если вы используете этот подход в нескольких местах, вы, возможно, захотите создать общий класс ComputingCache, чтобы избежать повторения логики.

2 голосов
/ 10 августа 2010

Если вы используете .NET 4.0, вы можете использовать удобный класс Lazy.

http://weblogs.asp.net/gunnarpeipman/archive/2009/05/19/net-framework-4-0-using-system-lazy-lt-t-gt.aspx

Если вы используете предыдущую версию фреймворка, вы можете просто написать свою собственную версию класса Lazy (это не особенно сложно).

2 голосов
/ 10 августа 2010

Храните свойства в перечислении и сохраняйте значения в хеш-таблице.Предоставьте один метод доступа к свойству.

не проверено:

enum MyProperties {
    Prop1,
    Prop2
}

// ...

static class PropertyProvider {
    static Hashtable<MyProperties, Object> cache = new Hashtable<MyProperties, Object>();
    static Object getProperty(MyProperties prop) {
        if (!cache.ContainsKey(prop)) {
            cache.add(prop, "SOMETHING");
        }

        return cache[prop];
    }
}

// ...

Object result = PropertyProvider.getProperty(MyProperties.Prop1);
1 голос
/ 10 августа 2010

ленивая часть важна?если нет, просто заполните все свойства во время ctor (все они могут быть автоматически), и все готово.Я бы предпочел сделать это, так как он не работает быстрее, если есть проблема с XML.Если lazy важен, то в .NET 4 вы можете использовать Lazy для них.

Обратите внимание, что при любом подходе к кешированию убедитесь, что: 1) у вас нет проблем переполнения стека в геттере и 2)пустые / отсутствующие значения по-прежнему считаются действительными для заполнения записи кэша (если это действительно так для исходного XML)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...