बहुत पुराना प्रश्न, लेकिन नया उत्तर ;-)
एक्सप्रेशनट्री वर्जन : (मुझे लगता है कि व्रत और सबसे साफ समाधान)
जैसे वेली तम्बुनन ने कहा, "हम वस्तु बनाने के लिए अभिव्यक्ति पेड़ का भी उपयोग कर सकते हैं"
यह दिए गए प्रकार / मापदंडों के लिए एक 'कंस्ट्रक्टर' (फ़ंक्शन) उत्पन्न करेगा। यह एक प्रतिनिधि को लौटाता है और पैरामीटर प्रकार को ऑब्जेक्ट की एक सरणी के रूप में स्वीकार करता है।
यह रहा:
// this delegate is just, so you don't have to pass an object array. _(params)_
public delegate object ConstructorDelegate(params object[] args);
public static ConstructorDelegate CreateConstructor(Type type, params Type[] parameters)
{
// Get the constructor info for these parameters
var constructorInfo = type.GetConstructor(parameters);
// define a object[] parameter
var paramExpr = Expression.Parameter(typeof(Object[]));
// To feed the constructor with the right parameters, we need to generate an array
// of parameters that will be read from the initialize object array argument.
var constructorParameters = parameters.Select((paramType, index) =>
// convert the object[index] to the right constructor parameter type.
Expression.Convert(
// read a value from the object[index]
Expression.ArrayAccess(
paramExpr,
Expression.Constant(index)),
paramType)).ToArray();
// just call the constructor.
var body = Expression.New(constructorInfo, constructorParameters);
var constructor = Expression.Lambda<ConstructorDelegate>(body, paramExpr);
return constructor.Compile();
}
उदाहरण MyClass:
public class MyClass
{
public int TestInt { get; private set; }
public string TestString { get; private set; }
public MyClass(int testInt, string testString)
{
TestInt = testInt;
TestString = testString;
}
}
उपयोग:
// you should cache this 'constructor'
var myConstructor = CreateConstructor(typeof(MyClass), typeof(int), typeof(string));
// Call the `myConstructor` function to create a new instance.
var myObject = myConstructor(10, "test message");
एक और उदाहरण: एक सरणी के रूप में प्रकारों को पारित करना
var type = typeof(MyClass);
var args = new Type[] { typeof(int), typeof(string) };
// you should cache this 'constructor'
var myConstructor = CreateConstructor(type, args);
// Call the `myConstructor` fucntion to create a new instance.
var myObject = myConstructor(10, "test message");
अभिव्यक्ति का डीबग व्यू
.Lambda #Lambda1<TestExpressionConstructor.MainWindow+ConstructorDelegate>(System.Object[] $var1) {
.New TestExpressionConstructor.MainWindow+MyClass(
(System.Int32)$var1[0],
(System.String)$var1[1])
}
यह उत्पन्न कोड के बराबर है:
public object myConstructor(object[] var1)
{
return new MyClass(
(System.Int32)var1[0],
(System.String)var1[1]);
}
छोटा सा उल्टा
जब वे ऑब्जेक्ट सरणी की तरह पास होते हैं तो सभी वैल्यूएटाइप्स पैरामीटर बॉक्स किए जाते हैं।
सरल प्रदर्शन परीक्षण:
private void TestActivator()
{
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < 1024 * 1024 * 10; i++)
{
var myObject = Activator.CreateInstance(typeof(MyClass), 10, "test message");
}
sw.Stop();
Trace.WriteLine("Activator: " + sw.Elapsed);
}
private void TestReflection()
{
var constructorInfo = typeof(MyClass).GetConstructor(new[] { typeof(int), typeof(string) });
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < 1024 * 1024 * 10; i++)
{
var myObject = constructorInfo.Invoke(new object[] { 10, "test message" });
}
sw.Stop();
Trace.WriteLine("Reflection: " + sw.Elapsed);
}
private void TestExpression()
{
var myConstructor = CreateConstructor(typeof(MyClass), typeof(int), typeof(string));
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < 1024 * 1024 * 10; i++)
{
var myObject = myConstructor(10, "test message");
}
sw.Stop();
Trace.WriteLine("Expression: " + sw.Elapsed);
}
TestActivator();
TestReflection();
TestExpression();
परिणाम:
Activator: 00:00:13.8210732
Reflection: 00:00:05.2986945
Expression: 00:00:00.6681696
का उपयोग करना Expressions
+/- 8 बार की तुलना में तेज है ConstructorInfo
और +/- का उपयोग करने की तुलना में 20 गुना तेज हैActivator