My code for creating new arrays was absurdly overkill -- there's a simple Linq expression that does everything in a one-liner, faster and safer

git-svn-id: file:///srv/devel/repo-conversion/nusu@236 d2e56fa2-650e-0410-a79f-9358c0239efd
This commit is contained in:
Markus Ewald 2012-02-06 09:50:15 +00:00
parent f5c282e840
commit 40231aa15c

View File

@ -181,15 +181,16 @@ namespace Nuclex.Support.Cloning {
int dimensionCount = clonedType.GetArrayRank(); int dimensionCount = clonedType.GetArrayRank();
int baseVariableIndex = variables.Count; int baseVariableIndex = variables.Count;
var arrayTransferExpressions = new List<Expression>();
Type elementType = clonedType.GetElementType(); Type elementType = clonedType.GetElementType();
// Retrieve the length of each of the array's dimensions // Retrieve the length of each of the array's dimensions
MethodInfo arrayGetLengthMethodInfo = typeof(Array).GetMethod("GetLength"); MethodInfo arrayGetLengthMethodInfo = typeof(Array).GetMethod("GetLength");
var lengths = new List<Expression>();
for(int index = 0; index < dimensionCount; ++index) { for(int index = 0; index < dimensionCount; ++index) {
ParameterExpression length = Expression.Variable(typeof(int)); ParameterExpression length = Expression.Variable(typeof(int));
variables.Add(length); variables.Add(length);
arrayTransferExpressions.Add( lengths.Add(length);
transferExpressions.Add(
Expression.Assign( Expression.Assign(
length, length,
Expression.Call( Expression.Call(
@ -199,78 +200,9 @@ namespace Nuclex.Support.Cloning {
); );
} }
// Create a new array of identical size and dimensions
switch(dimensionCount) {
case 1: {
MethodInfo arrayCreateInstanceMethodInfo = typeof(Array).GetMethod(
"CreateInstance", new Type[] { typeof(Type), typeof(int) }
);
arrayTransferExpressions.Add(
Expression.Assign(
clone,
Expression.Convert(
Expression.Call(
arrayCreateInstanceMethodInfo,
Expression.Constant(elementType),
variables[baseVariableIndex]
),
clonedType
)
)
);
break;
}
case 2: {
MethodInfo arrayCreateInstanceMethodInfo = typeof(Array).GetMethod(
"CreateInstance", new Type[] { typeof(Type), typeof(int), typeof(int) }
);
arrayTransferExpressions.Add(
Expression.Assign(
clone,
Expression.Convert(
Expression.Call(
arrayCreateInstanceMethodInfo,
Expression.Constant(elementType),
variables[baseVariableIndex],
variables[baseVariableIndex + 1]
),
clonedType
)
)
);
break;
}
case 3: {
MethodInfo arrayCreateInstanceMethodInfo = typeof(Array).GetMethod(
"CreateInstance", new Type[] { typeof(Type), typeof(int), typeof(int), typeof(int) }
);
arrayTransferExpressions.Add(
Expression.Assign(
clone,
Expression.Convert(
Expression.Call(
arrayCreateInstanceMethodInfo,
Expression.Constant(elementType),
variables[baseVariableIndex],
variables[baseVariableIndex + 1],
variables[baseVariableIndex + 2]
),
clonedType
)
)
);
break;
}
default: {
throw new InvalidOperationException("Unsupported array dimension count");
}
}
// Only execute the array transfer expressions if the array is not null
transferExpressions.Add( transferExpressions.Add(
Expression.IfThen( Expression.Assign(
Expression.NotEqual(original, Expression.Constant(null)), clone, Expression.NewArrayBounds(elementType, lengths)
Expression.Block(arrayTransferExpressions)
) )
); );
@ -404,6 +336,18 @@ namespace Nuclex.Support.Cloning {
/// <summary>Compiles a method that creates a clone of an object</summary> /// <summary>Compiles a method that creates a clone of an object</summary>
/// <param name="clonedType">Type for which a clone method will be created</param> /// <param name="clonedType">Type for which a clone method will be created</param>
/// <returns>A method that clones an object of the provided type</returns> /// <returns>A method that clones an object of the provided type</returns>
/// <remarks>
/// <para>
/// The 'null' check is supposed to take place before running the cloner. This
/// avoids having redundant 'null' checks on nested types - first before calling
/// GetType() on the field to be cloned and second when runner the matching
/// cloner for the field.
/// </para>
/// <para>
/// This design also enables the cloning of nested value types (which can never
/// be null) without any null check whatsoever.
/// </para>
/// </remarks>
private static Func<object, object> createDeepFieldBasedCloner(Type clonedType) { private static Func<object, object> createDeepFieldBasedCloner(Type clonedType) {
ParameterExpression original = Expression.Parameter(typeof(object), "original"); ParameterExpression original = Expression.Parameter(typeof(object), "original");