Dans mon architecture de plug-in, je passe actuellement un nom de plug-in (chaîne), un nom de méthode (chaîne) et des paramètres (tableau d'objets) à mon service de plug-in pour exécuter la méthode spécifiée et renvoyer le résultat (de type T).
La méthode execute du service de plugin est visible ci-dessous:
public TResult Execute<TResult>(string pluginName, string operation, params object[] input) {
MethodInfo method = null;
TResult result = default(TResult);
var plugin = _plugins.Enabled().FirstOrDefault(x => x.GetType().Name.Equals(pluginName, StringComparison.InvariantCultureIgnoreCase));
if (plugin != null) {
method = plugin.GetType().GetMethods().FirstOrDefault(x => x.Name == operation);
if (method != null) {
result = (TResult)method.Invoke(plugin, input);
}
}
return result;
}
Un exemple d'utilisation:
var url = AppHelper.PluginService.Execute<string>(
"ImagePlugin",
"GetImageUrl",
new object[] { image, size });
Ce que je préférerais faire, c’est plutôt de passer à un type anonyme (car je pense que cela est plus lisible), c.-à-d.
var url = AppHelper.PluginService.Execute<string>(
"ImagePlugin",
"GetImageUrl",
new { image = image, targetSize = size });
Comment pourrais-je changer ma méthode Execute pour mapper les propriétés de type anonyme sur les paramètres de ma méthode de plug-in?
J'avais envisagé d'utiliser le nouveau type dynamique dans .net 4.0, mais je préfère définir mes paramètres sur la méthode du plug-in plutôt que d'accepter un objet dynamique.
Merci Ben
[Mettre à jour]
Après avoir examiné le code source ASP.NET MVC, il semble assez simple d’extraire le type anonyme dans un dictionnaire d’objets, par exemple. RouteValueDictionary . À l'aide de la réflexion, une expression linq est créée de manière dynamique. Bien que ce soit une bonne implémentation, je ne voulais pas vraiment toute cette complexité supplémentaire.
Selon le commentaire ci-dessous, je peux atteindre la lisibilité simplement en spécifiant mes paramètres inline (pas besoin de la déclaration de tableau d'objets):
var url = AppHelper.PluginService.Execute<string>("ImagePlugin", "GetImageUrl", image, size);
Il y a plusieurs façons de rendre cela possible bien que je ne conseille à aucun d'entre eux.
Tout d'abord, vous pouvez utiliser la réflexion, ce qui signifie que vous devez écrire beaucoup de code supplémentaire (sujet aux erreurs) dans votre méthode PluginService.Execute
pour obtenir les valeurs souhaitées.
Deuxièmement, si vous connaissez les paramètres de type anonyme que vous transmettez à votre méthode, vous pouvez utiliser la technique décrite ici . Vous pouvez transtyper vers un autre type anonyme à l'intérieur de votre méthode qui possède les mêmes propriétés. Ici est une autre description de la même technique de Jon Skeet.
Troisièmement, vous pouvez utiliser les classes du System.ComponentModel
. Par exemple, ASP.NET MVC utilise cela. Il utilise la réflexion sous le capot. Cependant, dans ASP.NET MVC, les noms de propriété sont bien connus (controller
et action
par exemple) ou leurs noms importent peu, car ils sont passés tels quels à une méthode de contrôleur (id
par exemple).
J'ai finalement rencontré ce post qui illustre l'utilisation de types anonymes en tant que dictionnaires. En utilisant cette méthode, vous pouvez passer le type anonyme en tant que paramètre de méthode (objet) et accéder à ses propriétés.
Cependant, j'ajouterais qu'après avoir examiné les nouvelles fonctionnalités dynamiques de .net 4.0 telles que ExpandoObject, il est beaucoup plus simple de passer un objet dynamique en paramètre:
dynamic myobj = new ExpandoObject();
myobj.FirstName = "John";
myobj.LastName = "Smith";
SayHello(myobj);
...........
public static void SayHello(dynamic properties)
{
Console.WriteLine(properties.FirstName + " " + properties.LastName);
}
Utilisez un objet dynamique pour les paramètres si vous souhaitez passer un type anonyme. La méthode execute d'un plugin doit attendre certaines propriétés d'un objet paramètre pour fonctionner. En utilisant le mot clé dynamique, le compilateur C # sera informé de ne pas effectuer de vérification de type sur un paramètre et permettra d'utiliser une syntaxe fortement typée dans le code du plugin. La résolution du nom des propriétés se produira au moment de l'exécution et si un objet passé ne possédait pas de telles propriétés, une exception sera levée.
var o = new { FirstName = "John", LastName = "Doe" };
var result = MyMethod(o);
string MyMethod(dynamic o)
{
return o.FirstName + " " + o.LastName;
}
Cet exemple convertit un objet anonyme en dictionnaire:
IDictionary<string, object> AnonymousObjectToDictionary(object propertyBag)
{
var result = new Dictionary<string, object>();
if (propertyBag != null)
{
foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(propertyBag))
{
result.Add(property.Name, property.GetValue(propertyBag));
}
}
return result;
}
Vous pouvez l'appeler comme ça:
AnonymousObjectToDictionary(new { foo = 11, bar = "Be happy" });
Si c'est un type autonome de Linq, vous pouvez facilement le faire en passant IEnumerable.
Voici un exemple de méthode de réception
public static void MyMethod<IEnumType>(ref IEnumerable<IEnumType> ienum)
{
using (DataTable dt = new DataTable())
{
ienum.First(ie => true).GetType().GetProperties().ToList().ForEach(pr => dt.Columns.Add(pr.Name, typeof(string))); //Parallelization not possible since DataTable columns must be in certain order
ienum.ToList().ForEach(ie => //Parallelization not possible since DataTable rows not synchronized.
{
List<object> objAdd = new List<object>();
ie.GetType().GetProperties().ToList().ForEach(pr => objAdd.Add(ie.GetType().InvokeMember(pr.Name, BindingFlags.GetProperty, null, ie, null))); //Parallelization not possible since DataTable columns must be in certain order
dt.Rows.Add(objAdd.ToArray());
objAdd.Clear();
objAdd = null;
});
//Do something fun with dt
}
}
Bien sûr, puisque vous utilisez la réflexion, vous risquez de rencontrer des problèmes de performances sur les machines plus lentes ou lorsque vous avez un grand IEnumerable ou beaucoup de propriétés dans T.
Salut, j'ai écrit un post à ce sujet:
http://blog.jorgef.net/2011/06/converting-any-object-to-dynamic.html
J'espère que ça aide.
Je l'ai fait une fois. Ce que vous pouvez faire, c'est obtenir les paramètres attendus de la fonction par réflexion. Ensuite, vous pouvez construire votre tableau de paramètres en faisant correspondre les noms du tableau de paramètres avec les clés de l'objet anonyme.
J'espère que cela pourra aider :-).
public static void ExAnonymousType()
{
var nguoi = new { Ten = "Vinh", Tuoi = 20 };
Console.WriteLine(nguoi.Ten + " " + nguoi.Tuoi);
DoSomeThing(nguoi);
}
private static void DoSomeThing(object nguoi)
{
Console.WriteLine(nguoi.GetType().GetProperty("Ten").GetValue(nguoi,null));
}
Tout d’abord, vérifiez l’espace de noms System.Addin pour obtenir de l’aide.
Deuxièmement, vous pouvez créer votre propre interface avec un nom de méthode et des paramètres spécifiques, et laisser le plug-in l'implémenter. Vous pouvez définir une interface de plug-in dans un projet différent pouvant être référencé à la fois dans une application et dans un projet de plug-in.