C# ';缓存';性质

C# ';缓存';性质,c#,caching,properties,C#,Caching,Properties,我有一个充满属性的类。当访问属性时,它从XDocument中读取一些值 public class Foo { private XDocument root; public Foo(Stream str) { root = XDocument.load(str); } public String Bar { get { return root.Element("bar").Value; } } } 只是看起来有点开销,因为每次访问它时,它都必须再次读取X

我有一个充满属性的类。当访问属性时,它从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个属性。每次我都要做这个检查,既然OOP就是不复制大部分代码,有没有办法让它自动工作

将属性保留在枚举中,并将值缓存在哈希表中。提供单个属性访问器

未测试:

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);
enum MyProperties{
建议1,
建议2
}
// ...
静态类属性提供程序{
静态哈希表缓存=新哈希表();
静态对象getProperty(MyProperties属性){
如果(!cache.ContainsKey(prop)){
cache.add(道具,“某物”);
}
返回缓存[prop];
}
}
// ...
对象结果=PropertyProvider.getProperty(MyProperties.Prop1);

将属性保留在枚举中,并将值缓存在哈希表中。提供单个属性访问器

未测试:

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);
enum MyProperties{
建议1,
建议2
}
// ...
静态类属性提供程序{
静态哈希表缓存=新哈希表();
静态对象getProperty(MyProperties属性){
如果(!cache.ContainsKey(prop)){
cache.add(道具,“某物”);
}
返回缓存[prop];
}
}
// ...
对象结果=PropertyProvider.getProperty(MyProperties.Prop1);
正如前面提到的“最后一个”,每个属性没有一个字段。保留一个字典作为缓存,这样您就不用为尚未访问的属性支付任何费用

我建议你有一个方法,你可以提供检索实际值的机制。例如:

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); }
    }
}
公共类Foo
{
私有枚举缓存密钥
{
酒吧,巴兹。。。;
}
私有只读XDocument文档;
专用只读字典缓存;
私有字符串获取(CacheKey、Func计算)
{
字符串结果;
如果(!cache.TryGetValue(键,输出结果))
{
结果=计算(doc);
缓存[键]=结果;
}
返回结果;
}
公共字符串栏
{
获取{return Fetch(CacheKey.Bar,doc=>doc.Element(“Bar”).Value);}
}
}
这样一来,每个属性都相当紧凑——它基本上表示了所涉及的缓存键以及如何计算属性。如果需要不同类型的属性,您可能希望缓存将
TValue
作为
object
,并将
Fetch
方法设置为泛型,在必要时进行强制转换。不可否认,这最终将限制值类型

如果您在多个地方使用这种方法,那么您可能希望创建一个通用的
计算缓存
类,以避免重复该逻辑。

正如前面提到的“最后一个”,每个属性都没有一个字段。保留一个字典作为缓存,这样您就不用为尚未访问的属性支付任何费用

我建议你有一个方法,你可以提供检索实际值的机制。例如:

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); }
    }
}
公共类Foo
{
私有枚举缓存密钥
{
酒吧,巴兹。。。;
}
私有只读XDocument文档;
专用只读字典缓存;
私有字符串获取(CacheKey、Func计算)
{
字符串结果;
如果(!cache.TryGetValue(键,输出结果))
{
结果=计算(doc);
缓存[键]=结果;
}
返回结果;
}
公共字符串栏
{
获取{return Fetch(CacheKey.Bar,doc=>doc.Element(“Bar”).Value);}
}
}
这样一来,每个属性都相当紧凑——它基本上表示了所涉及的缓存键以及如何计算属性。如果需要不同类型的属性,您可能希望缓存将
TValue
作为
object
,并将
Fetch
方法设置为泛型,在必要时进行强制转换。不可否认,这最终将限制值类型


如果您在多个地方使用这种方法,您很可能希望创建一个通用的
计算缓存
类,以避免重复逻辑。

惰性部分重要吗?如果没有,只需在同一时间填充所有属性(它们都可以是自动的),就完成了。我宁愿这样做,因为如果xml有问题,它会更快地失败。如果懒惰很重要,那么在.NET4中,您可以使用懒惰


请注意,无论使用何种缓存方法,请确保1)getter中没有堆栈溢出问题,2)空/缺失值仍然被认为是填充缓存项的有效值(如果源xml确实如此)

延迟部分重要吗?如果没有,只需在同一时间填充所有属性(它们都可以是自动的),就完成了。我宁愿这样做,因为如果xml有问题,它会更快地失败。如果懒惰很重要,那么在.NET4中,您可以使用懒惰


请注意,无论采用何种缓存方法,请确保1)getter中没有堆栈溢出问题,2)空/缺失值仍然被认为是填充缓存项的有效值(如果源xml确实如此)

如果使用.NET 4.0,则可以使用handy Lazy类


如果您使用的是早期版本的框架,您可以编写自己版本的Lazy类(并不特别复杂)。

如果您使用的是.NET 4.0,您可以使用handy Lazy类


如果您使用的是以前版本的框架,您可以编写自己版本的Lazy类(它不是特别复杂)。

您确定没有过早地优化它吗?可能的重复您确定没有过早地优化它吗