bien, el alcance de la cuestión cambió pero mi observación original y oposición de algunas otras soluciones sigue en pie.
Creo que no puede/no quiere usar 'genéricos' aquí. No conoce el tipo con anticipación, y como deberá crear el tipo, no es necesario utilizar una implementación genérica porque MethodBase.Invoke toma una matriz de Object.
Este código asume que está instanciando el destino desde el campo de la base de datos. Si no solo ajuste en consecuencia.
Por supuesto, esto no abarca todo y no tiene un manejo de excepciones útil, pero le permitirá ejecutar dinámicamente métodos arbitrarios en un tipo arbitrario con valores de parámetros arbitrarios, todos provenientes de valores de cadena en una fila.
NOTA: hay muchos muchos escenarios en los que este simple ejecutor no funcionará. Tendrá que asegurarse de diseñar sus métodos dinámicos para cooperar con cualquier estrategia que termine decidiendo usar.
using System;
using System.ComponentModel;
using System.Drawing;
using System.Globalization;
using System.Reflection;
using NUnit.Framework;
namespace DynamicMethodInvocation
{
[TestFixture]
public class Tests
{
[Test]
public void Test()
{
// from your database
string assemblyQualifiedTypeName = "DynamicMethodInvocation.TestType, DynamicMethodInvocation";
string methodName = "DoSomething";
// this is how you would get the strings to put in your database
string enumString = Executor.ConvertToString(typeof(AttributeTargets), AttributeTargets.Assembly);
string colorString = Executor.ConvertToString(typeof(Color), Color.Red);
string stringString = "Hmm... String?";
object result = Executor.ExecuteMethod(assemblyQualifiedTypeName, methodName,
new[] { enumString, colorString, stringString });
Assert.IsInstanceOf<bool>(result);
Assert.IsTrue((bool)result);
}
}
public class TestType
{
public bool DoSomething(AttributeTargets @enum, Color color, string @string)
{
return true;
}
}
public class Executor
{
public static object ExecuteMethod(string assemblyQualifiedTypeName, string methodName,
string[] parameterValueStrings)
{
Type targetType = Type.GetType(assemblyQualifiedTypeName);
MethodBase method = targetType.GetMethod(methodName);
ParameterInfo[] pInfo = method.GetParameters();
var parameterValues = new object[parameterValueStrings.Length];
for (int i = 0; i < pInfo.Length; i++)
{
parameterValues[i] = ConvertFromString(pInfo[i].ParameterType, parameterValueStrings[i]);
}
// assumes you are instantiating the target from db and that it has a parameterless constructor
// otherwise, if the target is already known to you and instantiated, just use it...
return method.Invoke(Activator.CreateInstance(targetType), parameterValues);
}
public static string ConvertToString(Type type, object val)
{
if (val is string)
{
return (string) val;
}
TypeConverter tc = TypeDescriptor.GetConverter(type);
if (tc == null)
{
throw new Exception(type.Name + " is not convertable to string");
}
return tc.ConvertToString(null, CultureInfo.InvariantCulture, val);
}
public static object ConvertFromString(Type type, string val)
{
TypeConverter tc = TypeDescriptor.GetConverter(type);
if (tc == null)
{
throw new Exception(type.Name + " is not convertable.");
}
if (!tc.IsValid(val))
{
throw new Exception(type.Name + " is not convertable from " + val);
}
return tc.ConvertFrom(null, CultureInfo.InvariantCulture, val);
}
}
}
Creo que la palabra que busca es 'dinámicamente' en lugar de 'genéricamente'. Ha obtenido bastantes respuestas de kneejerk con ese uso cuando sus requisitos describen la necesidad de crear dinámicamente un valor de parámetro a partir de cadenas descriptivas. ¿Te entiendo bien? –
Mi otra pregunta para todos es: ¿Alguna vez alguien leyó y entendió completamente una pregunta antes de responder? Por Dios .... –
Ok, siguiente pregunta: ¿Sobre qué estás invocando métodos? ¿Un objeto instanciado existente que se conoce por el método de programación, o está instantando el objetivo también? –