Я не эксперт в динамической части С#, но, похоже, это работает правильно:
using System;
using System.Linq;
using System.Runtime.CompilerServices;
using Microsoft.CSharp.RuntimeBinder; // Requires reference to Microsoft.CSharp
public class ImplicitTest
{
public double Val { get; set; }
public ImplicitTest(double val)
{
this.Val = val;
}
public static implicit operator int(ImplicitTest d)
{
return (int)d.Val;
}
}
public class TestClass
{
public int Val { get; set; }
public TestClass(int val = 5)
{
this.Val = val;
}
public TestClass(int val1, int val2)
{
this.Val = val1 + val2;
}
public TestClass(int val1, int val2, int val3, int val4, int val5, int val6, int val7, int val8, int val9, int val10, int val11, int val12, int val13, int val14)
{
this.Val = val1 + val2 + val3 + val4 + val5 + val6 + val7 + val8 + val9 + val10 + val11 + val12 + val13 + val14;
}
}
public static class DynamicFactory
{
private static readonly CallSiteBinder callsiteBinder0 = Binder.InvokeConstructor(
CSharpBinderFlags.None,
typeof(DynamicFactory),
// It is OK to have too many arguments :-)
new CSharpArgumentInfo[]
{
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.IsStaticType | CSharpArgumentInfoFlags.UseCompileTimeType, null), // 0 parameters
});
private static readonly CallSiteBinder callsiteBinder = Binder.InvokeConstructor(
CSharpBinderFlags.None,
typeof(DynamicFactory),
// It is OK to have too many arguments :-)
// Note that this "feature" doesn't work correctly with Mono in the
// case of 0 arguments
new CSharpArgumentInfo[]
{
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.IsStaticType | CSharpArgumentInfoFlags.UseCompileTimeType, null), // 0 parameters
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null), // 1 parameter
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null), // 2 parameters
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null), // 14 parameters
});
// Quirk of Mono with 0 arguments. See callsiteBinder0
private static readonly CallSite<Func<CallSite, Type, object>> CallSite0 = CallSite<Func<CallSite, Type, object>>.Create(callsiteBinder0);
private static readonly CallSite<Func<CallSite, Type, object, object>> CallSite1 = CallSite<Func<CallSite, Type, object, object>>.Create(callsiteBinder);
private static readonly CallSite<Func<CallSite, Type, object, object, object>> CallSite2 = CallSite<Func<CallSite, Type, object, object, object>>.Create(callsiteBinder);
private static readonly CallSite<Func<CallSite, Type, object, object, object, object>> CallSite3 = CallSite<Func<CallSite, Type, object, object, object, object>>.Create(callsiteBinder);
private static readonly CallSite<Func<CallSite, Type, object, object, object, object, object>> CallSite4 = CallSite<Func<CallSite, Type, object, object, object, object, object>>.Create(callsiteBinder);
private static readonly CallSite<Func<CallSite, Type, object, object, object, object, object, object>> CallSite5 = CallSite<Func<CallSite, Type, object, object, object, object, object, object>>.Create(callsiteBinder);
private static readonly CallSite<Func<CallSite, Type, object, object, object, object, object, object, object>> CallSite6 = CallSite<Func<CallSite, Type, object, object, object, object, object, object, object>>.Create(callsiteBinder);
private static readonly CallSite<Func<CallSite, Type, object, object, object, object, object, object, object, object>> CallSite7 = CallSite<Func<CallSite, Type, object, object, object, object, object, object, object, object>>.Create(callsiteBinder);
private static readonly CallSite<Func<CallSite, Type, object, object, object, object, object, object, object, object, object>> CallSite8 = CallSite<Func<CallSite, Type, object, object, object, object, object, object, object, object, object>>.Create(callsiteBinder);
private static readonly CallSite<Func<CallSite, Type, object, object, object, object, object, object, object, object, object, object>> CallSite9 = CallSite<Func<CallSite, Type, object, object, object, object, object, object, object, object, object, object>>.Create(callsiteBinder);
private static readonly CallSite<Func<CallSite, Type, object, object, object, object, object, object, object, object, object, object, object>> CallSite10 = CallSite<Func<CallSite, Type, object, object, object, object, object, object, object, object, object, object, object>>.Create(callsiteBinder);
private static readonly CallSite<Func<CallSite, Type, object, object, object, object, object, object, object, object, object, object, object, object>> CallSite11 = CallSite<Func<CallSite, Type, object, object, object, object, object, object, object, object, object, object, object, object>>.Create(callsiteBinder);
private static readonly CallSite<Func<CallSite, Type, object, object, object, object, object, object, object, object, object, object, object, object, object>> CallSite12 = CallSite<Func<CallSite, Type, object, object, object, object, object, object, object, object, object, object, object, object, object>>.Create(callsiteBinder);
private static readonly CallSite<Func<CallSite, Type, object, object, object, object, object, object, object, object, object, object, object, object, object, object>> CallSite13 = CallSite<Func<CallSite, Type, object, object, object, object, object, object, object, object, object, object, object, object, object, object>>.Create(callsiteBinder);
private static readonly CallSite<Func<CallSite, Type, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object>> CallSite14 = CallSite<Func<CallSite, Type, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object>>.Create(callsiteBinder);
public static object Create(string typeName, params object[] args)
{
return Create(Type.GetType(typeName), args);
}
public static object Create(Type type, params object[] args)
{
if (type == null)
{
throw new ArgumentNullException("type");
}
if (args == null)
{
args = new object[0];
}
object obj;
switch (args.Length)
{
case 0:
// Quirk of Mono with 0 arguments. See callsiteBinder0
obj = CallSite0.Target(CallSite0, type);
break;
case 1:
obj = CallSite1.Target(CallSite1, type, args[0]);
break;
case 2:
obj = CallSite2.Target(CallSite2, type, args[0], args[1]);
break;
case 3:
obj = CallSite3.Target(CallSite3, type, args[0], args[1], args[2]);
break;
case 4:
obj = CallSite4.Target(CallSite4, type, args[0], args[1], args[2], args[3]);
break;
case 5:
obj = CallSite5.Target(CallSite5, type, args[0], args[1], args[2], args[3], args[4]);
break;
case 6:
obj = CallSite6.Target(CallSite6, type, args[0], args[1], args[2], args[3], args[4], args[5]);
break;
case 7:
obj = CallSite7.Target(CallSite7, type, args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
break;
case 8:
obj = CallSite8.Target(CallSite8, type, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
break;
case 9:
obj = CallSite9.Target(CallSite9, type, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
break;
case 10:
obj = CallSite10.Target(CallSite10, type, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]);
break;
case 11:
obj = CallSite11.Target(CallSite11, type, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10]);
break;
case 12:
obj = CallSite12.Target(CallSite12, type, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11]);
break;
case 13:
obj = CallSite13.Target(CallSite13, type, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12]);
break;
case 14:
obj = CallSite14.Target(CallSite14, type, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13]);
break;
default:
throw new ArgumentException("Too many parameters");
}
return obj;
}
}
public class Program
{
public static void Main()
{
try
{
Type monoRuntime = Type.GetType("Mono.Runtime");
if (monoRuntime != null)
{
System.Reflection.MethodInfo displayName = monoRuntime.GetMethod("GetDisplayName", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
if (displayName != null)
{
Console.WriteLine("Mono version {0}", displayName.Invoke(null, null));
}
}
TestClass tc0 = (TestClass)DynamicFactory.Create("TestClass");
TestClass tc1 = (TestClass)DynamicFactory.Create("TestClass", new ImplicitTest(1.0));
TestClass tc1b = (TestClass)DynamicFactory.Create("TestClass", 1);
TestClass tc2 = (TestClass)DynamicFactory.Create("TestClass", new ImplicitTest(1.0), new ImplicitTest(2.0));
TestClass tc14 = (TestClass)DynamicFactory.Create("TestClass", Enumerable.Range(0, 14).Select(x => new ImplicitTest((double)x)).ToArray());
Console.WriteLine(tc0.Val);
Console.WriteLine(tc1.Val);
Console.WriteLine(tc1b.Val);
Console.WriteLine(tc2.Val);
Console.WriteLine(tc14.Val);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
Он использует «динамическую» часть .NET. Он использует Microsoft.CSharp.RuntimeBinder, который "знает" правила привязки C#. Как заметил кто-то другой, определяемые пользователем неявные и явные приведения типов относятся к С#, а не к .NET, поэтому вам нужен связующий элемент, который «знает» о них. Идеальным решением было бы иметь подкласс класса System.Reflection.Binder, который «знает» правила C#. Тогда вы могли бы передать его Type.GetConstructor и жить счастливо. Жаль, что нет такой реализации.
Обратите внимание, что, к сожалению, делегат хранится в общем подклассе CallSite, CallSite<T>, где T является типом делегата. Именно поэтому большая switch инструкция.
Идея кода: https://ideone.com/NoQ67H. Обратите внимание, что в Mono есть особенность, поэтому конструкторы с нулевым параметром имеют специальную обработку.
person
xanatos
schedule
09.03.2016
implicit operator int— этоstatic, он не переопределяет ни один метод классаobject. И сActivator.CreateInstanceArgsвы проходитеobjects - person Matteo Umili   schedule 08.03.2016Microsoft.CSharpимеет правила C# для выбора перегрузки. См. ideone.com/UkGm4E . Я недостаточно опытен, чтобы перевести его на общий рабочий метод (динамический - не моя область С#) - person xanatos   schedule 08.03.2016