Let’s look at LINQ-to-Objects. How many inefficiencies are introduced by this code?
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;
}
I'm wondering about to many .Where .toArray .Union.
For example, the ToArray method doesn’t know the size of the output, so it must make many allocations. If we have array of ints instead of PropertyInfo it’ll start with 4 elements, and then keep doubling and copying elements as necessary. And we may end up with excess storage. If we end up with 33,000 elements, for example, we will waste about 128KB of dynamic storage (32,000 X 4-byte ints).
Also when I find passwordProperties there are two delegate object allocations, two for the call to Enumerable.Where. These delegates point to potentially two distinct closure objects, each of which has captured enclosing variables. These closure objects are instances of new classes, which occupy nontrivial space in both the binary and at runtime. (And of course, the arguments are now stored in two places, must be copied to the closure objects, and then we must incur extra indirections each time we access them.) In all likelihood, the Where operators are going to allocate new IEnumerable objects.
How can I improve code by using declarative manner (because it’ll just get faster as the compiler and runtimes enjoy new optimizations)?