为缓存

时间:2016-12-19 20:29:19

标签: c# asp.net caching

编辑:以下所有答案(截至2016年12月19日)都有助于做出决定。我接受了对我的问题最全面的回答;但最终选择简单地散列文件。

我正在缓存对象并使用程序集版本作为密钥的一部分,以在每次构建更改时使缓存的对象失效。这是低效的,因为缓存对象的实际类很少更改并且在构建中有效。

如何使用密钥的特定类签名(基本上所有属性)的哈希值,以便它只在类本身更改时更改?

我可以想到使用反射的一种有点复杂的方式,但我想知道是否有一个我缺少的简单技巧或任何编译时机制。

谢谢!

E.g。 Foo的签名 - > #ABCD

public class Foo {
    public string Bar {get; set;}
}

Foo的新签名(属性类型已更改) - > #WXYZ

public class Foo {
    public char[] Bar {get; set;}
}

4 个答案:

答案 0 :(得分:1)

您可以散列整个类文件并将其用作键。当文件发生变化时,哈希值会发生变化,这将满足您的需求

答案 1 :(得分:1)

您可以使用该类的公共属性,并根据每个属性的名称和类型生成一个哈希:

int ComputeTypeHash<T>()
{
    return typeof(T).GetProperties()
        .SelectMany(p => new[] { p.Name.GetHashCode(), p.PropertyType.GetHashCode() })
        .Aggregate(17, (h, x) => unchecked(h * 23 + x));
}
ComputeTypeHash<Foo_v1>().Dump(); // 1946663838
ComputeTypeHash<Foo_v2>().Dump(); // 1946663838
ComputeTypeHash<Foo_v3>().Dump(); // 1985957629

public class Foo_v1
{
    public string Bar { get; set; }
}
public class Foo_v2
{
    public string Bar { get; set; }
}

public class Foo_v3
{
    public char[] Bar { get; set; }
}

答案 2 :(得分:1)

正如其他人所指出的,做类似的事情是危险的,因为签名并没有定义其背后的逻辑。那很难过:

这是一种可扩展的方法:

该方法基本上使用反射来遍历您的类型的所有属性。
然后它获取这些属性的一些特定值,并在它们上调用ToString()
这些值将附加到stringGetHashCode()将用于该字符串。

private int GetTypeHash<T>()
{
    var propertiesToCheck = typeof(T).GetProperties();

    if(propertiesToCheck == null || propertiesToCheck.Length == 0)
        return 0;

    StringBuilder sb = new StringBuilder();

    foreach(var propertyToCheck in propertiesToCheck)
    {
        //Some simple things that could change:
        sb.Append((int)propertyToCheck.Attributes);
        sb.Append(propertyToCheck.CanRead);
        sb.Append(propertyToCheck.CanWrite);
        sb.Append(propertyToCheck.IsSpecialName);
        sb.Append(propertyToCheck.Name);
        sb.Append(propertyToCheck.PropertyType.AssemblyQualifiedName);

        //It might be an index property
        var indexParams = propertyToCheck.GetIndexParameters();
        if(indexParams != null && indexParams.Length != 0)
        {
            sb.Append(indexParams.Length);
        }

        //It might have custom attributes
        var customAttributes = propertyToCheck.CustomAttributes;
        if(customAttributes != null)
        {
            foreach(var cusAttr in customAttributes)
            {
                sb.Append(cusAttr.GetType().AssemblyQualifiedName);
            }
        }
    }

    return sb.ToString().GetHashCode();
}

答案 3 :(得分:1)

做这样的事情很危险,因为你(或其他人)可能会在某些时候将逻辑引入属性本身。它也可能是属性对其他改变的方法(以及其他方面)进行内部调用。你不会发现超出签名的变化,这样你就会对灾难敞开大门。

如果您提到的这些类很少更改,请考虑将它们从主程序集中移出并放入自己的程序集中,或者如果有意义的话,将其分解为多个程序集。这样他们的程序集就不会改变版本,也不会有缓存刷新。