编辑:以下所有答案(截至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;}
}
答案 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()
。
这些值将附加到string
,GetHashCode()
将用于该字符串。
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)
做这样的事情很危险,因为你(或其他人)可能会在某些时候将逻辑引入属性本身。它也可能是属性对其他改变的方法(以及其他方面)进行内部调用。你不会发现超出签名的变化,这样你就会对灾难敞开大门。
如果您提到的这些类很少更改,请考虑将它们从主程序集中移出并放入自己的程序集中,或者如果有意义的话,将其分解为多个程序集。这样他们的程序集就不会改变版本,也不会有缓存刷新。