Динамически и производительный вызов для добавления метода на DbSet - PullRequest
0 голосов
/ 24 октября 2011

Я хотел бы сделать динамический вызов метода Add в DbSet, который я не знаю при компиляции.

На самом деле, это возможно с простым отражением, но производительность ужасна.Вот код, который мы используем сейчас:

Type contextType = (context as Object).GetType();
var set = (contextType.GetProperty(entitySetName)).GetValue(context, null);
Type typeSet = set.GetType();
MethodInfo method = typeSet.GetMethod("Add");

Object[] args = { entity };

method.Invokke(set, args);

я пробовал две другие возможности с разными ошибками.

Первый - использование делегата

public delegate void MyDel<T>(T t,object entity);

Type contextType = (context as Object).GetType();
var set = (contextType.GetProperty(entitySetName)).GetValue(context, null);
Type typeSet = set.GetType();
MethodInfo method = typeSet.GetMethod("Add");

Type template = typeof(MyDel<>);
Type specific = template.MakeGenericType(childClassType);
Delegate test = Delegate.CreateDelegate(specific, method);

но в последней строке я получаю следующую ошибку: Ошибка привязки к целевому методу

И третий вариант - использовать дерево выражений следующим образом:

Type contextType = (context as Object).GetType();
var set = (contextType.GetProperty(entitySetName)).GetValue(context, null);
Type typeSet = set.GetType();
MethodInfo method = typeSet.GetMethod("Add");


ParameterExpression paramo = Expression.Parameter(typeSet, "param");
ParameterExpression parami = Expression.Parameter(typeSet, "newvalue");
Expression convertedParamo = Expression.Convert(paramo, typeof(Object));
Expression convertedParami = Expression.Convert(parami, typeof(Object));

MethodCallExpression methodCall = Expression.Call(convertedParamo, method, convertedParami);                    

Expression valueExp = Expression.Lambda(methodCall, paramo, parami);
Expression<Action<Object, Object>> dynamicExpression = (Expression<Action<Object, Object>>)valueExp;
Action<Object, Object> dynamicAction = dynamicExpression.Compile();

Object o = Activator.CreateInstance(otherType);
dynamicAction(o, entity);

Но в этом случаев строке "Expression.Call (convertParamo, метод, ..

я получил эту ошибку:

Метод 'DictionnaireONYX.Entites.ArticleSansFacturier Добавить (DictionnaireONYX.Entites.ArticleSansFacturier)'объявленный для типа 'System.Data.Entity.DbSet`1 [DictionnaireONYX.Entites.ArticleSansFacturier]' не может быть вызван с экземпляром типа System.Object *

, где ArticleSansFacturier - это DbSet.

Кто может мне помочь?

Заранее спасибо

Ответы [ 2 ]

0 голосов
/ 24 октября 2011

Если вы используете .NET 4.0, вы можете использовать ключевое слово «dynamic» - это лучший и наиболее эффективный способ.Это будет выглядеть примерно так:

Type contextType = (context as Object).GetType();
dynamic set = (contextType.GetProperty(entitySetName)).GetValue(context, null);
set.Add(args);

Я не уверен, что понимаю ваш код на 100%, поэтому не уверен, что это именно то, что вы пытаетесь сделать, но это общая идея.

Дополнительная литература: http://msdn.microsoft.com/en-us/library/dd264736.aspx

0 голосов
/ 24 октября 2011

Я должен сказать, что сейчас не знаю, какова производительность, но после внесения нескольких изменений в ваш код, похоже, он работает. Особенно динамическая часть в конце может создать некоторые проблемы.

Я использовал ModelContext с установленным в нем Автором.

ModelContext context = new ModelContext();

Author entity = new Author();

string entitySetName = "Authors";
string methodName = "AddObject";

Type contextType = (context as Object).GetType();
var set = (contextType.GetProperty(entitySetName)).GetValue(context, null);
Type typeSet = set.GetType();
MethodInfo method = typeSet.GetMethod(methodName);

ParameterExpression paramo = Expression.Parameter(typeSet, "param");
ParameterExpression parami = Expression.Parameter(entity.GetType(), "newvalue");

MethodCallExpression methodCall = Expression.Call(paramo, method, parami);

Type typeofClassWithGenericStaticMethod = typeof(Expression);
MethodInfo methodInfo = typeofClassWithGenericStaticMethod.GetMethods().Where(m => m.Name == "Lambda" && m.IsGenericMethod).First();
Type genericArguments = typeof(Action<,>).MakeGenericType(typeSet, entity.GetType());
MethodInfo genericMethodInfo = methodInfo.MakeGenericMethod(genericArguments);

dynamic objectSet = set;
dynamic returnValue = genericMethodInfo.Invoke(null, new object[] { methodCall, new ParameterExpression[] { paramo, parami } });
var action = returnValue.Compile();

action(objectSet, entity);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...