I was looking for a long time how to call ExpandoObject methods or DynamicObject heirs through reflection. On the Internet I found the library Dynamitey . But it does not work with .Net Core
Closed due to the fact that the essence of the question is not clear to the party PashaPash ♦ 14 Jul '16 at 14:34 .
Try to write more detailed questions. To get an answer, explain what exactly you see the problem, how to reproduce it, what you want to get as a result, etc. Give an example that clearly demonstrates the problem. If the question can be reformulated according to the rules set out in the certificate , edit it .
2 answers
I was looking for a solution for Speakers for a long time (IDynamicMetaObjectProvider) found the solution https://gist.github.com/jflam/777574 https://github.com/mgravell/fast-member/blob/master/FastMember/CallSiteCache.cs
Based on made for all sorts of DynamicObject
using System.Text; using System.Threading.Tasks; using System.Linq.Expressions; using Microsoft.CSharp.RuntimeBinder; using System.Dynamic; using System.Runtime.CompilerServices; namespace Тестовый { public class DynamicInvoker { public static object InvokeMember(object target, string methodName, params object[] args) { var targetParam = CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null); CSharpArgumentInfo[] parameterFlags = new CSharpArgumentInfo[args.Length + 1]; System.Linq.Expressions.Expression[] parameters = new System.Linq.Expressions.Expression[args.Length + 1]; parameterFlags[0] = targetParam; parameters[0] = System.Linq.Expressions.Expression.Constant(target); for (int i = 0; i < args.Length; i++) { parameterFlags[i + 1] = CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.Constant | CSharpArgumentInfoFlags.UseCompileTimeType, null); parameters[i + 1] = System.Linq.Expressions.Expression.Constant(args[i]); } var csb = Binder.InvokeMember(CSharpBinderFlags.None, methodName, null, typeof(DynamicInvoker), parameterFlags); var de = DynamicExpression.Dynamic(csb, typeof(object), parameters); LambdaExpression expr = System.Linq.Expressions.Expression.Lambda(de); return expr.Compile().DynamicInvoke(); } public static object GetValue(object target,string name) { CallSite<Func<CallSite, object, object>> callSite = CallSite<Func<CallSite, object, object>>.Create(Binder.GetMember(CSharpBinderFlags.None, name, typeof(DynamicInvoker), new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) })); return callSite.Target(callSite, target); } public static void SetValue(object target, string name, object value) { CallSite<Func<CallSite, object, object, object>> callSite = CallSite<Func<CallSite, object, object, object>>.Create(Binder.SetMember(CSharpBinderFlags.None, name, typeof(DynamicInvoker), new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null) })); callSite.Target(callSite, target, value); } } }
And challenge
void ВывестиСвойство(object target, string ИмяСвойства) { textBox.AppendText(ИмяСвойства+"="+DynamicInvoker.GetValue(target, ИмяСвойства).ToString() + Environment.NewLine); } private void button_Click(object sender, RoutedEventArgs e) { dynamic res = new ExpandoObject(); res.Имя = "Тест ExpandoObject"; res.Число = 456; res.ВСтроку = (Func<string>)(() => res.Имя); res.Сумма = (Func<int,int,int>)((x,y) => x+y); textBox.Clear(); textBox.AppendText("ВСтроку="+DynamicInvoker.InvokeMember(res, "ВСтроку").ToString()+Environment.NewLine); textBox.AppendText("Сумма=" + DynamicInvoker.InvokeMember(res, "Сумма", 1, 2).ToString() + Environment.NewLine); ВывестиСвойство(res, "Имя"); ВывестиСвойство(res, "Число"); DynamicInvoker.SetValue(res, "Имя","Новое Имя"); DynamicInvoker.SetValue(res, "Число","768"); ВывестиСвойство(res, "Имя"); ВывестиСвойство(res, "Число"); }
Checked on .Net Core. Works. Soon I will lay out the component with the support of objects supporting IDynamicMetaObjectProvider
You can also use the heir DynamicObject
class TestDynamicObject : DynamicObject { public override bool TrySetMember(SetMemberBinder binder, object value) { return true; } // получение свойства public override bool TryGetMember(GetMemberBinder binder, out object result) { result = binder.Name; return true; } // вызов метода public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) { var res = new StringBuilder("{0}("); var param = new object[args.Length + 1]; param[0] = binder.Name; if (args.Length > 0) { Array.Copy(args, 0, param, 1, args.Length); for (int i = 0; i < args.Length; i++) { res.AppendFormat("{{{0}}},", i + 1); } res.Remove(res.Length - 1, 1); } res.Append(")"); result = String.Format(res.ToString(), param); return true; }
And an example of a call for example from 1C
Тестовый=ъТип("TestDllForCoreClr.Тестовый, TestDllForCoreClr, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"); Тест=ъ(Врап.Новый(Тестовый.ПолучитьСсылку()," Свойство из Конструктора")); // Это аналог структуры, но с поддержкой методов РасширяемыйОбъект=ъ(Тест.ПолучитьExpandoObject()); Сообщить("ВСтроку="+РасширяемыйОбъект.ВСтроку()); Сообщить("Сумма=" + РасширяемыйОбъект.Сумма(1, 2)); Сообщить(РасширяемыйОбъект.Имя); Сообщить(РасширяемыйОбъект.Число); РасширяемыйОбъект.Имя="Новое Имя"; РасширяемыйОбъект.Число=768; // Добавим новое свойство РасширяемыйОбъект.НовоеСвойство="Новое Свойство"; Сообщить(РасширяемыйОбъект.Имя); Сообщить(РасширяемыйОбъект.Число); Сообщить(РасширяемыйОбъект.НовоеСвойство); НовыйРеквизит=ъ(Врап.Новый("System.Dynamic.ExpandoObject, System.Dynamic.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")); НовыйРеквизит.Имя="Новый Реквизит"; НовыйРеквизит.Значение=123; РасширяемыйОбъект.НовыйРквизит=НовыйРеквизит.ПолучитьСсылку(); Сообщить(ъ(РасширяемыйОбъект.НовыйРквизит).Имя); TestDynamicObject=ъТип("TestDllForCoreClr.TestDynamicObject, TestDllForCoreClr, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"); ДинамикОбъект=ъНовый(TestDynamicObject.ПолучитьСсылку()); ДинамикОбъект.УстановимЛюбоеСвойство="Чего то там"; Сообщить( ДинамикОбъект.ПолучитТоЧтоПередали); Сообщить(ДинамикОбъект.ПолучитТоЧтоПередалиСПараметрами(1,3.45,ТекущаяДата())); Сообщить(ДинамикОбъект.Ъ(1,3.45,ТекущаяДата())); Сообщить(Тест.ПолучитьАтрибутыПараметра()); Сообщить(Тест.СравнитьАтрибуты()); // product=ъНовый("Newtonsoft.Json.Linq.JObject, Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed"); product=ъНовый("Newtonsoft.Json.Linq.JObject, Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed"); product.ProductName = "Elbow Grease"; product.Enabled = true; product.Price = 4.90; product.StockCount = 9000; product.StockValue = 44100; DecompressionMethods= ъТип("System.Net.DecompressionMethods, System.Net.Primitives, Version=4.0.11.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); // 'System.Runtime.Serialization.Primitives, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' JArray=ъТип("Newtonsoft.Json.Linq.JArray, Newtonsoft.Json, Version=4.0.11.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed"); массив=ъ(Врап.Новый(JArray.ПолучитьСсылку(),"Real","OnSale")); product.Tags =массив.ПолучитьСсылку(); Сообщить(product.ToString());
Unfortunately, Newtonsoft.Json for .Net Core does not work ToString () because it uses the System.Runtime.Serialization.Primitives library which in .Net Core is not
IDictionary<string, object>
? - VladD