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:
parent
f5c282e840
commit
40231aa15c
|
@ -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");
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user