fastest way to construct a struct from a type?

N

not_a_commie

It seems that the only way to construct a struct from a type is to use
Activator.CreateInstance. Is that true? Can anyone improve
(performance-wise) upon this function below:


/// <summary>
/// Create an object of the given type
/// A default constructor is required to be successful.
/// A failure will return null.
/// </summary>
/// <param name="type">The type of the object to create.</param>
/// <param name="constructorParams">Arguments for the desired
constructor.</param>
public static object CreateObject(Type type, params object[]
constructorParams)
{
if (type == null)
throw new ArgumentNullException("Type");
try
{
if (type.IsArray)
{
int[] dimensions = new int[constructorParams.Length];
for (int i = 0; i < constructorParams.Length; i++)
dimensions = (int)constructorParams;
return Array.CreateInstance(type.GetElementType(), dimensions);
}
else if (type == typeof(string))
{
return "";
}
else
{
// the easy and slow way:
//return Activator.CreateInstance(type, constructorParams);
if (constructorParams == null || constructorParams.Length <= 0)
{
ConstructorInfo ci = type.GetConstructor(Type.EmptyTypes);
if (ci == null) // stupid structs and their default
constructors....
return Activator.CreateInstance(type); // it does cache the most
recent 16 types

DynamicMethod dm = new DynamicMethod("MyCtor", type,
Type.EmptyTypes, typeof(ClassFactory).Module, true);
ILGenerator ilgen = dm.GetILGenerator();
ilgen.Emit(OpCodes.Nop);
ilgen.Emit(OpCodes.Newobj, ci);
ilgen.Emit(OpCodes.Ret);
return ((CtorDelegate)dm.CreateDelegate(typeof(CtorDelegate)))();
// we could cache these delegates with a type lookup
// but preparation time is really very minimal
// see here: http://blogs.msdn.com/haibo_luo/archive/2005/11/17/494009.aspx
// and here: http://blogs.msdn.com/haibo_luo/articles/494008.aspx
}
else
{
Type[] constructorTypes = new Type[constructorParams.Length];
for (int i = 0; i < constructorParams.Length; i++)
constructorTypes = constructorParams.GetType();
// DynamicMethod is not quite as fast in this case
// where we don't have a delegate matching the function
// This should be really rare in deserialization, though
ConstructorInfo ci = type.GetConstructor(constructorTypes);
if (ci == null) // stupid structs and their default
constructors....
return Activator.CreateInstance(type); // it does cache the most
recent 16 types

return ci.Invoke(constructorParams);
}
// another thing we could do is cache IClonables and just return
cloned copies in that case
}
}
catch (Exception e)
{
if (e.InnerException is LicenseException)
throw e.InnerException;
throw new ClassFactoryException("Error constructing object " +
type.Name, e);
}
}
private delegate object CtorDelegate();
 
N

Nicholas Paldino [.NET/C# MVP]

Curious, can you create a generic version of this and then use
default(T) (where T is the type parameter)? If you can, then that might be
the easiest, and most maintainable solution.

Of course, if you are loading the type information (loading the name of
the type, that is) and don't have access to it at compile time, it won't
help.

Other than that, you can probably still go down the dynamic code
generation route. I would recommend an interface which would return an
object, and you would then create dynamic types implementing that interface.
It would imply create an instance of your structure for you. Then, you
would have a dictionary keyed by type which would return this interface
implementation, and then just call the method to return a new instance of
the value type.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

not_a_commie said:
It seems that the only way to construct a struct from a type is to use
Activator.CreateInstance. Is that true? Can anyone improve
(performance-wise) upon this function below:


/// <summary>
/// Create an object of the given type
/// A default constructor is required to be successful.
/// A failure will return null.
/// </summary>
/// <param name="type">The type of the object to create.</param>
/// <param name="constructorParams">Arguments for the desired
constructor.</param>
public static object CreateObject(Type type, params object[]
constructorParams)
{
if (type == null)
throw new ArgumentNullException("Type");
try
{
if (type.IsArray)
{
int[] dimensions = new int[constructorParams.Length];
for (int i = 0; i < constructorParams.Length; i++)
dimensions = (int)constructorParams;
return Array.CreateInstance(type.GetElementType(), dimensions);
}
else if (type == typeof(string))
{
return "";
}
else
{
// the easy and slow way:
//return Activator.CreateInstance(type, constructorParams);
if (constructorParams == null || constructorParams.Length <= 0)
{
ConstructorInfo ci = type.GetConstructor(Type.EmptyTypes);
if (ci == null) // stupid structs and their default
constructors....
return Activator.CreateInstance(type); // it does cache the most
recent 16 types

DynamicMethod dm = new DynamicMethod("MyCtor", type,
Type.EmptyTypes, typeof(ClassFactory).Module, true);
ILGenerator ilgen = dm.GetILGenerator();
ilgen.Emit(OpCodes.Nop);
ilgen.Emit(OpCodes.Newobj, ci);
ilgen.Emit(OpCodes.Ret);
return ((CtorDelegate)dm.CreateDelegate(typeof(CtorDelegate)))();
// we could cache these delegates with a type lookup
// but preparation time is really very minimal
// see here:
http://blogs.msdn.com/haibo_luo/archive/2005/11/17/494009.aspx
// and here: http://blogs.msdn.com/haibo_luo/articles/494008.aspx
}
else
{
Type[] constructorTypes = new Type[constructorParams.Length];
for (int i = 0; i < constructorParams.Length; i++)
constructorTypes = constructorParams.GetType();
// DynamicMethod is not quite as fast in this case
// where we don't have a delegate matching the function
// This should be really rare in deserialization, though
ConstructorInfo ci = type.GetConstructor(constructorTypes);
if (ci == null) // stupid structs and their default
constructors....
return Activator.CreateInstance(type); // it does cache the most
recent 16 types

return ci.Invoke(constructorParams);
}
// another thing we could do is cache IClonables and just return
cloned copies in that case
}
}
catch (Exception e)
{
if (e.InnerException is LicenseException)
throw e.InnerException;
throw new ClassFactoryException("Error constructing object " +
type.Name, e);
}
}
private delegate object CtorDelegate();
 
B

Ben Voigt [C++ MVP]

Nicholas Paldino said:
Curious, can you create a generic version of this and then use
default(T) (where T is the type parameter)? If you can, then that might
be the easiest, and most maintainable solution.

Of course, if you are loading the type information (loading the name of
the type, that is) and don't have access to it at compile time, it won't
help.

Other than that, you can probably still go down the dynamic code
generation route. I would recommend an interface which would return an

No dynamic code generation needed (well the JIT will be generating code, but
it always does that).
object, and you would then create dynamic types implementing that
interface. It would imply create an instance of your structure for you.
Then, you would have a dictionary keyed by type which would return this
interface implementation, and then just call the method to return a new
instance of the value type.

For the zero (or fixed) parameter case, construct a delegate from the
ConstructorInfo and store those in a dictionary. Then creating multiples of
the same type is as cheap as a delegate call.

See http://msdn2.microsoft.com/en-us/library/53cz7sc6.aspx
--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

not_a_commie said:
It seems that the only way to construct a struct from a type is to use
Activator.CreateInstance. Is that true? Can anyone improve
(performance-wise) upon this function below:


/// <summary>
/// Create an object of the given type
/// A default constructor is required to be successful.
/// A failure will return null.
/// </summary>
/// <param name="type">The type of the object to create.</param>
/// <param name="constructorParams">Arguments for the desired
constructor.</param>
public static object CreateObject(Type type, params object[]
constructorParams)
{
if (type == null)
throw new ArgumentNullException("Type");
try
{
if (type.IsArray)
{
int[] dimensions = new int[constructorParams.Length];
for (int i = 0; i < constructorParams.Length; i++)
dimensions = (int)constructorParams;
return Array.CreateInstance(type.GetElementType(), dimensions);
}
else if (type == typeof(string))
{
return "";
}
else
{
// the easy and slow way:
//return Activator.CreateInstance(type, constructorParams);
if (constructorParams == null || constructorParams.Length <= 0)
{
ConstructorInfo ci = type.GetConstructor(Type.EmptyTypes);
if (ci == null) // stupid structs and their default
constructors....
return Activator.CreateInstance(type); // it does cache the most
recent 16 types

DynamicMethod dm = new DynamicMethod("MyCtor", type,
Type.EmptyTypes, typeof(ClassFactory).Module, true);
ILGenerator ilgen = dm.GetILGenerator();
ilgen.Emit(OpCodes.Nop);
ilgen.Emit(OpCodes.Newobj, ci);
ilgen.Emit(OpCodes.Ret);
return ((CtorDelegate)dm.CreateDelegate(typeof(CtorDelegate)))();
// we could cache these delegates with a type lookup
// but preparation time is really very minimal
// see here:
http://blogs.msdn.com/haibo_luo/archive/2005/11/17/494009.aspx
// and here: http://blogs.msdn.com/haibo_luo/articles/494008.aspx
}
else
{
Type[] constructorTypes = new Type[constructorParams.Length];
for (int i = 0; i < constructorParams.Length; i++)
constructorTypes = constructorParams.GetType();
// DynamicMethod is not quite as fast in this case
// where we don't have a delegate matching the function
// This should be really rare in deserialization, though
ConstructorInfo ci = type.GetConstructor(constructorTypes);
if (ci == null) // stupid structs and their default
constructors....
return Activator.CreateInstance(type); // it does cache the most
recent 16 types

return ci.Invoke(constructorParams);
}
// another thing we could do is cache IClonables and just return
cloned copies in that case
}
}
catch (Exception e)
{
if (e.InnerException is LicenseException)
throw e.InnerException;
throw new ClassFactoryException("Error constructing object " +
type.Name, e);
}
}
private delegate object CtorDelegate();

 
B

Ben Voigt [C++ MVP]

Ben Voigt said:
No dynamic code generation needed (well the JIT will be generating code,
but it always does that).


For the zero (or fixed) parameter case, construct a delegate from the
ConstructorInfo and store those in a dictionary. Then creating multiples
of the same type is as cheap as a delegate call.

See http://msdn2.microsoft.com/en-us/library/53cz7sc6.aspx

Sorry, this won't work because Delegate.CreateDelegate takes a parameter of
type MethodInfo, not MethodBase. My mistake.
--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

not_a_commie said:
It seems that the only way to construct a struct from a type is to use
Activator.CreateInstance. Is that true? Can anyone improve
(performance-wise) upon this function below:


/// <summary>
/// Create an object of the given type
/// A default constructor is required to be successful.
/// A failure will return null.
/// </summary>
/// <param name="type">The type of the object to create.</param>
/// <param name="constructorParams">Arguments for the desired
constructor.</param>
public static object CreateObject(Type type, params object[]
constructorParams)
{
if (type == null)
throw new ArgumentNullException("Type");
try
{
if (type.IsArray)
{
int[] dimensions = new int[constructorParams.Length];
for (int i = 0; i < constructorParams.Length; i++)
dimensions = (int)constructorParams;
return Array.CreateInstance(type.GetElementType(), dimensions);
}
else if (type == typeof(string))
{
return "";
}
else
{
// the easy and slow way:
//return Activator.CreateInstance(type, constructorParams);
if (constructorParams == null || constructorParams.Length <= 0)
{
ConstructorInfo ci = type.GetConstructor(Type.EmptyTypes);
if (ci == null) // stupid structs and their default
constructors....
return Activator.CreateInstance(type); // it does cache the most
recent 16 types

DynamicMethod dm = new DynamicMethod("MyCtor", type,
Type.EmptyTypes, typeof(ClassFactory).Module, true);
ILGenerator ilgen = dm.GetILGenerator();
ilgen.Emit(OpCodes.Nop);
ilgen.Emit(OpCodes.Newobj, ci);
ilgen.Emit(OpCodes.Ret);
return ((CtorDelegate)dm.CreateDelegate(typeof(CtorDelegate)))();
// we could cache these delegates with a type lookup
// but preparation time is really very minimal
// see here:
http://blogs.msdn.com/haibo_luo/archive/2005/11/17/494009.aspx
// and here: http://blogs.msdn.com/haibo_luo/articles/494008.aspx
}
else
{
Type[] constructorTypes = new Type[constructorParams.Length];
for (int i = 0; i < constructorParams.Length; i++)
constructorTypes = constructorParams.GetType();
// DynamicMethod is not quite as fast in this case
// where we don't have a delegate matching the function
// This should be really rare in deserialization, though
ConstructorInfo ci = type.GetConstructor(constructorTypes);
if (ci == null) // stupid structs and their default
constructors....
return Activator.CreateInstance(type); // it does cache the most
recent 16 types

return ci.Invoke(constructorParams);
}
// another thing we could do is cache IClonables and just return
cloned copies in that case
}
}
catch (Exception e)
{
if (e.InnerException is LicenseException)
throw e.InnerException;
throw new ClassFactoryException("Error constructing object " +
type.Name, e);
}
}
private delegate object CtorDelegate();


 
M

Marc Gravell

For info, if you are using .NET 3.5, you can use the Expression
namespace to do this without having to mess with the IL directly.
Example below - results first:

ConstructorInfo: 15564 [1000000]
Func: 52 [1000000]

So it takes 1/300th the time, which is nice.

Code follows; most of it is the test rig, and much of the rest could
be refactored to simplify [Jon - might fit in with ExpressionUtil -
would that make sense to you?]

using System;
using System.Linq.Expressions;
using System.Reflection;
using System.Diagnostics;
interface INamed { string Name { get; } int Counter { get; } }
class Demo : INamed {
public string Name { get; private set; }
public int Counter { get { return 1; } } // for checksum
public Demo(string name) {
Name = name;
}
}
class Program {
static void Main() {
Type type = typeof(Demo); // in reality by name of as a plugin
ConstructorInfo ci = type.GetConstructor(new[]
{typeof(string)});
ParameterExpression param =
Expression.Parameter(typeof(string), "name");
Func<string,INamed> ctor = Expression.Lambda<Func<string,
INamed>>(
Expression.New(ci, param), param).Compile();

const int COUNT = 1000000;
Stopwatch watch = new Stopwatch();

ci.Invoke(new[] { "hi" }); // for JIT
int check = 0;
watch.Start();
for (int i = 0; i < COUNT; i++) {
INamed instance = (INamed) ci.Invoke(new[] { "hi" });
check += instance.Counter;
}
watch.Stop();
Console.WriteLine("ConstructorInfo: {0} [{1}]",
watch.ElapsedMilliseconds, check);
watch.Reset();

ctor("hi"); // for JIT
check = 0;
watch.Start();
for (int i = 0; i < COUNT; i++) {
INamed instance = ctor("hi");
check += instance.Counter;
}
watch.Stop();
Console.WriteLine("Func: {0} [{1}]",
watch.ElapsedMilliseconds, check);


}
}
 
M

Marc Gravell

Refactored helper methods, to allow simple usage, i.e.

Type type = typeof(Demo); // however you get this!
var ctor = type.Ctor<string, INamed>();

i.e. a ctor that accepts a string, and we'll treat the result as an
INamed since such things are commonly based on an
interface/base-class. If not, can use Ctor<string, object>

Marc

-----------

public static Func<TResult> Ctor<TResult>(this Type type) {
ConstructorInfo ci = type.GetConstructor(Type.EmptyTypes);

return Expression.Lambda<Func<TResult>>(
Expression.New(ci)).Compile();
}
public static Func<TArg1, TResult> Ctor<TArg1, TResult>(this Type
type) {
ConstructorInfo ci = type.GetConstructor(new[] {
typeof(TArg1) });
ParameterExpression param1 =
Expression.Parameter(typeof(TArg1), "arg1");

return Expression.Lambda<Func<TArg1, TResult>>(
Expression.New(ci, param1), param1).Compile();
}
public static Func<TArg1, TArg2, TResult> Ctor<TArg1, TArg2,
TResult>(this Type type) {
ConstructorInfo ci = type.GetConstructor(new[] {
typeof(TArg1), typeof(TArg2) });
ParameterExpression param1 =
Expression.Parameter(typeof(TArg1), "arg1"),
param2 = Expression.Parameter(typeof(TArg2), "arg2");

return Expression.Lambda<Func<TArg1, TArg2, TResult>>(
Expression.New(ci, param1, param2), param1,
param2).Compile();
}
public static Func<TArg1, TArg2, TArg3, TResult> Ctor<TArg1,
TArg2, TArg3, TResult>(this Type type) {
ConstructorInfo ci = type.GetConstructor(new[] {
typeof(TArg1), typeof(TArg2), typeof(TArg3) });
ParameterExpression param1 =
Expression.Parameter(typeof(TArg1), "arg1"),
param2 = Expression.Parameter(typeof(TArg2), "arg2"),
param3 = Expression.Parameter(typeof(TArg3), "arg3");

return Expression.Lambda<Func<TArg1, TArg2, TArg3, TResult>>(
Expression.New(ci, param1, param2, param3), param1,
param2, param3).Compile();
}
public static Func<TArg1, TArg2, TArg3, TArg4, TResult>
Ctor<TArg1, TArg2, TArg3, TArg4, TResult>(this Type type) {
ConstructorInfo ci = type.GetConstructor(new[] {
typeof(TArg1), typeof(TArg2), typeof(TArg3), typeof(TArg4) });
ParameterExpression param1 =
Expression.Parameter(typeof(TArg1), "arg1"),
param2 = Expression.Parameter(typeof(TArg2), "arg2"),
param3 = Expression.Parameter(typeof(TArg3), "arg3"),
param4 = Expression.Parameter(typeof(TArg4), "arg4");

return Expression.Lambda<Func<TArg1, TArg2, TArg3, TArg4,
TResult>>(
Expression.New(ci, param1, param2, param3, param4),
param1, param2, param3, param4).Compile();
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top