动态且高性能地调用 DbSet 上的添加方法

发布于 2024-12-11 12:56:21 字数 2305 浏览 0 评论 0原文

我想对 DbSet 上的 Add 方法进行动态调用,但我在编译时不知道该方法。

实际上,通过简单的反射就可以实现,但性能很糟糕。这是我们现在使用的代码:

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(convertedParamo)”行,方法,..

我收到此错误:

方法'DictionnaireONYX.Entites.ArticleSansFacturier Add(DictionnaireONYX.Entites.ArticleSansFacturier)' 在类型上声明 'System.Data.Entity.DbSet`1[DictionnaireONYX.Entites.ArticleSansFacturier]' 无法使用“System.Object”类型的实例进行调用

,其中 ArticleSansFacturier 是 DbSet。

谁能帮助我?

提前致谢

i would like to make a dynamic call on the Add method on DbSet that i don't know at the compilation.

Actually, it's possible with simple reflection but the performance are awful. Here is the code we are using now :

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);

i've tried two others possibilities with different errors.

The first other is to use delegate

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);

but on the last line, i get the following error : Error binding to target method

And the third option is to use expression tree like this :

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);

But in this case, at the line "Expression.Call(convertedParamo, method,..

i got this error :

Method 'DictionnaireONYX.Entites.ArticleSansFacturier
Add(DictionnaireONYX.Entites.ArticleSansFacturier)' declared on type
'System.Data.Entity.DbSet`1[DictionnaireONYX.Entites.ArticleSansFacturier]'
cannot be called with instance of type 'System.Object'

where ArticleSansFacturier is the DbSet.

Who can help me ?

Thanks in advance

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

甜点 2024-12-18 12:56:21

我不得不说,我现在不知道性能如何,但对代码进行一些更改后,它似乎可以工作。尤其是最后的动态部分可能会出现一些问题。

我使用了 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);

I have to say I don't now how the performance is but after making a few changes to your code it seems to work. Especially the dynamic part at the end could give some problems.

I'v used a ModelContext with a Authors set in it.

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);
壹場煙雨 2024-12-18 12:56:21

如果您使用 .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

If you are using .NET 4.0 you can use the "dynamic" keyword - that's the best and most performant way.
It will look something like this:

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

I'm not sure I understand your code 100%, so not sure that's exactly what you are trying to do, but that's the general idea.

Further reading:
http://msdn.microsoft.com/en-us/library/dd264736.aspx

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文