Nie jestem ekspertem w dynamicznej części C#, ale to wydaje się działać poprawnie :
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);
}
}
}
Wykorzystuje "dynamiczną" część .NET.Korzysta z Microsoft.CSharp.RuntimeBinder, który "zna" wiążące reguły C#. Jak ktoś zauważył, zdefiniowane przez użytkownika niejawne i jawne rzuty są czymś w rodzaju C#, a nie .NET, więc potrzebujesz spinacza, który "wie" o nich. Idealnym rozwiązaniem byłoby posiadanie podklasy klasy System.Reflection.Binder
, która "zna" reguły C#. Następnie możesz przekazać go do Type.GetConstructor
i żyć szczęśliwy. Niestety nie ma takiej realizacji.
Należy zauważyć, że niestety delegat jest przechowywany w ogólnej podklasie o wartości CallSite
, CallSite<T>
, przy czym T
jest typem delegowanym. Z tego powodu duża instrukcja switch
.
Ideone kodu: https://ideone.com/NoQ67H. Zauważ, że w Mono występuje dziwactwo, więc konstruktorzy parametrów 0 mają specjalne możliwości.
Podobny wątek, który może pomóc: http://stackoverflow.com/questions/20932208/activator-createinstance-not-working-for-implicit-cast-scenario –
Ponieważ 'niejawny operator int' to' statyczny' , więc nie zastępuje żadnej metody klasy 'object'. A z 'Activator.CreateInstance'' Args', które przechodzisz to 'object's –
Możliwe jest wykorzystanie dynamicznej infrastruktury .NET. Zestaw 'Microsoft.CSharp' ma" reguły "C# do wyboru przeciążenia. Zobacz https://ideone.com/UkGm4E. Nie jestem ekspertem na tyle, aby przetłumaczyć go na "ogólną" metodę pracy (dynamiczne nie jest moim polem C#). – xanatos