C# 如何使用声明性方式而不是LINQ来提高性能?
让我们看看LINQ to对象。该代码引入了多少低效率C# 如何使用声明性方式而不是LINQ来提高性能?,c#,linq,C#,Linq,让我们看看LINQ to对象。该代码引入了多少低效率 public object GetObjectToSerialize(object value, Type targetType) { var type = value.GetType(); PropertyInfo[] setToNullProperties; if (!_typeToPropertyMap.TryGetValue(type, out setToNullProperties)) {
public object GetObjectToSerialize(object value, Type targetType)
{
var type = value.GetType();
PropertyInfo[] setToNullProperties;
if (!_typeToPropertyMap.TryGetValue(type, out setToNullProperties))
{
var allPropeties = type.GetProperties();
var passwordProperties = allPropeties
.Where(p => p.PropertyType == typeof(string))
.Where(p => p.Name.Contains("Password")).ToArray();
var passwordWithoutEncryptedAttribute = passwordProperties
.Where(p => !p.GetCustomAttributes(typeof(EncryptedConfigurationItemAttribute), false).Any());
if (passwordWithoutEncryptedAttribute.Any())
{
throw new InvalidOperationException();
}
var propertiesWithEncryptedAttribute = allPropeties.Where(p => p.GetCustomAttributes(typeof(EncryptedConfigurationItemAttribute), false).Any());
setToNullProperties = passwordProperties.Union(propertiesWithEncryptedAttribute).ToArray();
_typeToPropertyMap[type] = setToNullProperties;
}
foreach (var property in setToNullProperties)
{
property.SetValue(value, null, null);
}
return value;
}
我想知道有多少个.Where
.toArray
.Union
例如,ToArray
方法不知道输出的大小,因此必须进行多次分配。如果我们有int
s数组,而不是PropertyInfo
,它将从4个元素开始,然后根据需要继续加倍和复制元素。我们最终可能会有过多的存储空间。例如,如果我们最终使用33000
元素,我们将浪费大约128KB
的动态存储(32000 X 4字节整数
)
另外,当我找到passwordProperties
时,有两个委托对象分配,两个用于调用Enumerable.Where
。这些委托指向两个可能不同的闭包对象,每个对象都捕获了封闭变量。这些闭包对象是新类的实例,它们在二进制文件和运行时都占用了非平凡的空间。(当然,参数现在存储在两个地方,必须复制到闭包对象,然后每次访问它们时都必须进行额外的间接操作。)很可能,Where
操作符将分配新的IEnumerable
对象
如何使用声明式方式改进代码(因为随着编译器和运行时享受新的优化,它会变得更快)?if中的代码对每种类型执行一次。我看不出有什么问题。即使它比必要的速度慢2倍,它仍然足够快,并且很少执行(免责声明:我编写了该代码:-) 但是你问如何加速代码。。。您可以删除几乎所有LINQ:
public object GetObjectToSerialize(object value, Type targetType)
{
var type = value.GetType();
PropertyInfo[] setToNullProperties;
if (!_typeToPropertyMap.TryGetValue(type, out setToNullProperties))
{
PropertyInfo[] allProperties = type.GetProperties();
var setToNullProperties2 = new List<PropertyInfo>(allProperties);
foreach (PropertyInfo property in allProperties)
{
bool isEncrypted = property.GetCustomAttributes(typeof(EncryptedConfigurationItemAttribute), false).Any();
bool isPasswordProperty = false;
if (!isEncrypted)
{
isPasswordProperty = property.PropertyType == typeof(string) && property.Name.Contains("Password");
if (isPasswordProperty) {
throw new InvalidOperationException();
}
}
if (isEncrypted || isPasswordProperty) {
setToNullProperties2.Add(property);
}
}
_typeToPropertyMap[type] = setToNullProperties = setToNullProperties2.ToArray();
}
foreach (var property in setToNullProperties)
{
property.SetValue(value, null, null);
}
return value;
}
公共对象GetObjectToSerialize(对象值,类型targetType)
{
var type=value.GetType();
PropertyInfo[]setToNullProperties;
if(!\u typeToPropertyMap.TryGetValue(type,out setToNullProperties))
{
PropertyInfo[]allProperties=type.GetProperties();
var setToNullProperties2=新列表(所有属性);
foreach(所有属性中的PropertyInfo属性)
{
bool isEncrypted=property.GetCustomAttributes(typeof(EncryptedConfigurationItemAttribute),false);
bool isPasswordProperty=false;
如果(!已加密)
{
isPasswordProperty=property.PropertyType==typeof(字符串)和&property.Name.Contains(“密码”);
if(isPasswordProperty){
抛出新的InvalidOperationException();
}
}
如果(isEncrypted | | isPasswordProperty){
setTonullProperties 2.添加(属性);
}
}
_TypeTopPropertyMap[type]=setToNullProperties=setToNullProperties 2.ToArray();
}
foreach(setToNullProperties中的var属性)
{
SetValue(value,null,null);
}
返回值;
}
真正的加速将是在
表达式
树生成器中转换代码,因此您将删除重复反射(设置值部分)。问题是生成表达式
树并编译它相当慢,因此,除非您在同一类型
上使用GetObjectToSerialize
数百次,否则不会有加速。如果我们最终得到33000个元素
如果您在名称中包含“Password”的类型字符串的33.000个属性上运行此操作,您的问题不是Linq。if
中的代码对每种类型执行一次。我看不出有什么问题。即使它比必要的速度慢2倍,它仍然足够快,而且很少执行(免责声明:我写的代码:-),为什么需要反射?也许找到原因可以帮助你加快速度。我完全同意@xanatos。我还想提到的是,所使用的LINQ构造都没有引入闭包。