DynamicObject. How execute function through TryInvoke? - c#

I want to execute static functions through DynamicObject, but I don't know how execute saveOperation without specifying the class name typeof(Test1) or typeof(Test2) . How relise this better?
For example
class DynObj : DynamicObject
{
GetMemberBinder saveOperation;
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
saveOperation = binder;
result = this;
return true;
}
public override bool TryInvoke(InvokeBinder binder, object[] args, out object result)
{
Type myType = typeof(Test1 or Test2 or ....);
result = myType.GetMethod(saveOperation.Name).Invoke(null, args);
return true;
}
}
class Program
{
static void Main(string[] args)
{
dynamic d1 = new DynObj();
d1.func1(3,6);
d1.func2(3,6);
}
}
class Test1
{
public static void func1(int a, int b){...}
}
class Test2
{
public static void func2(int a, int b){ ...}
}
Second way defines static function with attribute ( offered by Carnifex )
class Test3
{
[DynFuncMemberAttribute]
public static void func3(int a, int b){...}
}
and get type
public override bool TryInvoke(InvokeBinder binder, object[] args, out object result)
{
Type myType = null;
foreach (Type types in Assembly.GetExecutingAssembly().GetTypes())
{
foreach (MethodInfo mi in types.GetMethods())
{
foreach (CustomAttributeData cad in mi.CustomAttributes)
{
if (cad.AttributeType == typeof(DynFuncMemberAttribute))
{
myType = types;
break;
}
}
}
}
result = (myType != null)? myType.GetMethod(saveOperation.Name).Invoke(null, args): null;
return myType != null;
}

You could use some Attributes and set eg. [DynFuncMemberAttribute] to the class or to the method it self.
Then inside TryInvoke (or constructor) get all types/methods marked with this attribute, build some map/cache and voila :)
Edit: this is example of use this attribute. Remember that BuildCache() will throw exception if two method with the same name will be found.
[AttributeUsage(AttributeTargets.Method)]
class DynFuncMemberAttribute : Attribute
{
}
class DynObj : DynamicObject
{
Dictionary<string, MethodInfo> cache;
GetMemberBinder saveOperation;
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
saveOperation = binder;
result = this;
return true;
}
public override bool TryInvoke(InvokeBinder binder, object[] args, out object result)
{
if (cache == null)
cache = BuildCache();
MethodInfo mi;
if (cache.TryGetValue(saveOperation.Name, out mi))
{
result = mi.Invoke(null, args);
return true;
}
result = null;
return false;
}
private Dictionary<string, MethodInfo> BuildCache()
{
return Assembly.GetEntryAssembly()
.GetTypes()
.SelectMany(t => t.GetMethods(BindingFlags.Public | BindingFlags.Static))
.Where(mi => mi.GetCustomAttribute<DynFuncMemberAttribute>() != null)
.ToDictionary(mi => mi.Name);
}
}
class Program
{
static void Main(string[] args)
{
dynamic d1 = new DynObj();
d1.func1(3, 6);
d1.func2(3, 6);
}
}
class Test1
{
[DynFuncMember]
public static void func1(int a, int b)
{
Console.WriteLine("func1");
}
}
class Test2
{
[DynFuncMember]
public static void func2(int a, int b)
{
Console.WriteLine("func2");
}
}

Related

Let DynamicObect's TryGetMember and TrySetMember return a class in C#

I have a class inheriting from DynamicObject
In this class I have a TryGetMember that I try to evaluate to a static class.
How can TryGetMember overriden from DynamicObject result in a static class?
TL;DR
Calling code:
dynamic sut = new ReachIn();
sut.myclass.MyInnerStaticClass.MyProperty= "fortytwo";
My DynamicObject class tries to return myclass as the MyClass instance.
internal class ReachIn : DynamicObject
{
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = MyClass; // Does not compile.
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
value = MyClass // Does not compile;
return true;
}
}
and what is returned is here:
internal class MyClass
{
internal static class MyInnerStaticClass
{
public static string MyProperty { get; set; }
}
}
This example is a bit forced. It is just a very simplified example of a dynamic object making private fields, properties, methods (and (not yet) classes) visible for testing purpose. I also know one should not write tests this way but I have an esoteric reason. or because I can.
Regardless of your class design I am going to show that what you are trying to achieve is possible with dynamic types and reflection. Firstly a dynamic object is just an object that can take some string name in method like TryGetMember to perform some action. Secondly with string names and reflection you can perform any operation on your objects. So simple dynamic object implementation that will work with your example looks like this:
internal class ReachIn : DynamicObject
{
private readonly Type type;
private readonly string #namespace;
public ReachIn(Type type = null, string #namespace = null)
{
this.type = type;
this.#namespace = #namespace;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (type == null)
{
result = new ReachIn(Type.GetType($"{#namespace}.{binder.Name}".Trim('.')));
return true;
}
var member = type.GetMember(binder.Name).Single();
if (member.MemberType == MemberTypes.NestedType)
{
result = new ReachIn((Type)member);
}
else if (member.MemberType == MemberTypes.Property)
{
result = ((PropertyInfo)member).GetValue(null);
}
else
{
result = null;
return false;
}
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
var member = type.GetMember(binder.Name).Single();
if (member.MemberType == MemberTypes.Property)
{
((PropertyInfo)member).SetValue(null, value);
return true;
}
return false;
}
}
So it will work for a sample class with public modifiers:
public class MyClass
{
public static class MyInnerStaticClass
{
public static string MyProperty { get; set; }
}
}
With this you can set your static property like:
dynamic sut = new ReachIn(#namespace: "ConsoleApp8");
sut.MyClass.MyInnerStaticClass.MyProperty = "safd";
It's tested only with your example so for other cases you would need to provide some additional implementation. Not to mention the performance of it would be very bad because of reflection.

c# DynamicObject class dynamic properties from loop

So I've created a class that inherits DynamicObject
public class MyDynamicObject : DynamicObject{
private Dictionary<string, object> Fields = new Dictionary<string, object>();
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
return Fields.TryGetValue(binder.Name, out result);
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
Fields[binder.Name] = value;
return true;
}
}
And call this class here
public class Program
{
public static void Main()
{
dynamic person = new MyDynamicObject();
person.firstname = "Hello";
Console.WriteLine(person.firstname);
}
}
Of course this will work. But I need to create properties from a string array like
string[] fields = new string[]{"taxid","newcol","addrs","gender"};
dynamic person = new MyDynamicObject();
foreach(var f in fields)
{
person.f = "hello";
}
So the output will be person.taxi, person.newcol, person.addrs, person.gender
Is this possible?
Expose the Fields dictionary in some way, or (better) a method that allows one to explicitly set a property by name.
Note that ExpandoObject already does this, as it can be cast to IDictionary<string, object> and then you
ExpandoObject eo = new ExpandoObject();
IDictionary<string, object> dict = eo;
dynamic d = eo;
dict["MyProperty"] = 42;
Console.WriteLine(d.MyProperty); // 42
If you can't just use ExpandoObject itself, you can copy its approach.
Okay so based on the suggestion of #Jon Hanna, I came up with a solution that fits my requirements. I created a new Add method which accept a name. Below is the updated code I used.
public class DynamicFormData : DynamicObject
{
private Dictionary<string, object> Fields = new Dictionary<string, object>();
public int Count { get { return Fields.Keys.Count; } }
public void Add(string name, string val = null)
{
if (!Fields.ContainsKey(name))
{
Fields.Add(name, val);
}
else
{
Fields[name] = val;
}
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (Fields.ContainsKey(binder.Name))
{
result = Fields[binder.Name];
return true;
}
return base.TryGetMember(binder, out result);
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
if (!Fields.ContainsKey(binder.Name))
{
Fields.Add(binder.Name, value);
}
else
{
Fields[binder.Name] = value;
}
return true;
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
if (Fields.ContainsKey(binder.Name) &&
Fields[binder.Name] is Delegate)
{
Delegate del = Fields[binder.Name] as Delegate;
result = del.DynamicInvoke(args);
return true;
}
return base.TryInvokeMember(binder, args, out result);
}
}
Then I just call it like this.
string[] fields = new string[]{"taxid","newcol","addrs","gender"};
dynamic formData = new DynamicFormData();
foreach(string field in fields)
{
formData.Add(field, null);
}

How do I/can I dynamically extend a c# object with methods that exist on another object?

Say that I have an object a, which is of class A:
abstract class A {
public abstract SomeType SomeMethod(int i)
public abstract SomeType SomeOtherMethod()
}
Can I/how do I create an object b, of class B - which, at run time, can take any object (say A), and wrap it:
class B {
public void Wrap(object someObject) {}
}
such that i can write the following code:
var a = Factory.BuildAn<A>();
var b = new B();
b.Wrap(a);
b.SomeMethod(1);
Am not sure what problem you're trying to solve with this, but here's what you asked.
class MyClass
{
public int IntValue { get; set; }
public string SomeMethod(int i)
{
return i.ToString();
}
public string SomeOtherMethod()
{
return "Hello";
}
}
class Wrapper : DynamicObject
{
private object wrappedObject;
public Wrapper(object wrappedObject)
{
this.wrappedObject = wrappedObject;
}
private void Wrap(object someObject)
{
wrappedObject = someObject;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
PropertyInfo prop = wrappedObject.GetType()
.GetProperty(binder.Name, BindingFlags.Instance | BindingFlags.Public);
if (prop == null)
{
result = null;
return false;
}
result = prop.GetValue(wrappedObject, null);
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
PropertyInfo prop = wrappedObject.GetType()
.GetProperty(binder.Name, BindingFlags.Instance | BindingFlags.Public);
if (prop == null)
{
return false;
}
prop.SetValue(wrappedObject, value);
return true;
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
MethodInfo method = wrappedObject.GetType()
.GetMethod(binder.Name, BindingFlags.Instance | BindingFlags.Public);
if (method == null)
{
result = null;
return false;
}
result = method.Invoke(wrappedObject, args);
return true;
}
}
MyClass a = new MyClass();
dynamic d = new Wrapper(a);
d.IntValue = 5;
string s = d.SomeOtherMethod();
Console.WriteLine(a.IntValue);
Yes you can using dynamic typing in C#. Class B will look like this, and you will use it exactly how you use it in your question.
class B : DynamicObject
{
object _object;
public void Wrap(object someObject)
{
_object = someObject;
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
try
{
result = _object.GetType().InvokeMember(
binder.Name,
BindingFlags.InvokeMethod |
BindingFlags.Public |
BindingFlags.Instance,
null, _object, args);
return true;
}
catch
{
result = null;
return false;
}
}
}

How cast Generic T to Action<...> to get the Method params

Hi i'm try to cast a generic to an Action with a unknown number and type of Parameters
at the moment it looks like:
public class subscriber
{
public subscriber()
{
new Subscription<Action>(a);
new Subscription<Action<string>>(b);
new Subscription<Action<int,string>>(c);
}
private void a() { }
private void b(string gg){}
private void c(int i, string g) { }
}
public class Subscription<T>
{
public T MyAction {get {retun _action;}}
public Type MyActionType {get;private set;}
public Subscription( T action )
{
MyAction = action;
MyActionType = action.GetType();
var gg = action.GetType().GetGenericArguments();// Contains the Sub generics
}
}
at the moment we know it will be an Action and we also know the Sub Types but how to put this all together
to execute my private void c(int i, string g) method
Final Goal
is to execute the Action from a Third-Class (which will contains a List<Subscription> ) when a Fourth-Class hand over some params
public abstract class SubscriptionBase
{
public abstract void ExecuteAction(params object[] parameters);
}
public class Subscription<T> : SubscriptionBase
{
private T _action;
public Subscription(T a)
{
_action = a;
}
public override void ExecuteAction(params object[] parameters)
{
(_action as Delegate).DynamicInvoke(parameters);
}
}
and you can use it like;
Action<int> func1 = (q) => q += 1;
Action<int, int> func2 = (q, w) => q += w;
Subscription<Action<int>> s1 = new Subscription<Action<int>>(func1);
Subscription<Action<int, int>> s2 = new Subscription<Action<int, int>>(func2);
List<SubscriptionBase> subscriptionBase = new List<SubscriptionBase>();
subscriptionBase.Add(s1);
subscriptionBase.Add(s2);
subscriptionBase[1].ExecuteAction(1, 2);
You can't do it that way. You can't put a Subscription<Action<int>> into the same list as Subscription<Action<string, Foo>>.
I suggest, you create an interface like the following and store those in your third class:
interface IActionExecutor
{
bool CanExecuteForParameters(params object[] parameters);
void Execute(params object[] parameters);
}
// Implementation for one parameter
// You need to create one class per additional parameter.
// This is similar to the Action delegates in the framework.
// You can probably extract a base class here that implements
// some of the repetitive pars
public class ActionExecutor<in T> : IActionExecutor
{
private Action<T> _action;
public ActionExecutor(Action<T> action)
{
if(action == null) throw new ArgumentNullException("action");
_action = action;
}
public bool CanExecuteForParameters(params object[] parameters)
{
if(parameters == null) throw new ArgumentNullException("action");
if(parameters.Length != 1) return false;
return parameters[0] is T;
}
public void Execute(params object[] parameters)
{
if(parameters == null) throw new ArgumentNullException("action");
if(parameters.Length != 1)
throw new ArgumentOutOfRangeException("action");
_action((T)parameters[0]);
}
}
In your third class you would have the list of IActionExecutors:
List<IActionExecutor> _subscriptions;
And you would use it like this:
public void Execute(params object[] parameters)
{
var matchingSubscriptions =
_subscriptions.Where(x => x.CanExecuteForParameters(parameters);
foreach(var subscription in matchingSubscriptions)
subscription.Execute(parameters);
}
To simplify the creation of those ActionExecutor instances, you can provide a factory class:
public static class ActionExecutor
{
public IActionExecutor Create(Action action)
{
return new ActionExecutor(action);
}
public IActionExecutor Create<T>(Action<T> action)
{
return new ActionExecutor<T>(action);
}
public IActionExecutor Create<T1, T2>(Action<T1, T2> action)
{
return new ActionExecutor<T1, T2>(action);
}
// ... and so on
}
Usage would now be like this:
_subscriptions.Add(ActionExecutor.Create(a));
_subscriptions.Add(ActionExecutor.Create(b));
_subscriptions.Add(ActionExecutor.Create(c));

C# dynamic classes

I'm talking about something similar to dynamic. This didn't answer my question, hence this question. I want to have a class that I can add properties to at runtime. It needs to be inherited from the type object.
I've seen inheriting from DynamicObject, but it didn't state how to add properties at run-time. Could some light be shed on this for me pls?
I have a class like this:
public class SomeModel : DynamicObject {
public string SomeMandatoryProperty {get; set;}
}
I'd like to add all properties from another class to this class at runtime. So eg.
SomeModel m = new SomeModel();
m = someOtherClass;
string hi = m.otherClassProp; //Property from other class is added.
string mandatory = m.SomeMandatoryProperty; //From the mandatory property set previously.
I think you are looking for ExpandoObject:
The ExpandoObject class enables you to
add and delete members of its
instances at run time and also to set
and get values of these members. This
class supports dynamic binding, which
enables you to use standard syntax
like sampleObject.sampleMember instead
of more complex syntax like
sampleObject.GetAttribute("sampleMember").
dynamic manager;
manager = new ExpandoObject();
manager.Name = "Allison Brown";
manager.Age = 42;
manager.TeamSize = 10;
You should be able to make use of ExpandoObject instead. An ExpandoObject can have members added or removed at runtime and has very nice support if you want to convert to XML etc.
From MSDN Documentation:
dynamic employee, manager;
employee = new ExpandoObject();
employee.Name = "John Smith";
employee.Age = 33;
manager = new ExpandoObject();
manager.Name = "Allison Brown";
manager.Age = 42;
manager.TeamSize = 10;
You'd want to use the ExpandoObject as you can dynamically add properties as needed. There isn't however a direct way to populate an instance with the values from another object easily. You'll have to add it manually using reflection.
Do you want to write a wrapper object where you could add properties to while still accessing the inner? You may want to consider it that way you don't have to manage two copies of values between two different object instances. I wrote a test class to wrap string objects to demonstrate how you can do this (similar to how the ExpandoObject works). It should give you an idea on how you can do this for your types.
class DynamicString : DynamicObject
{
static readonly Type strType = typeof(string);
private string instance;
private Dictionary<string, object> dynProperties;
public DynamicString(string instance)
{
this.instance = instance;
dynProperties = new Dictionary<string, object>();
}
public string GetPrefixString(string prefix)
{
return String.Concat(prefix, instance);
}
public string GetSuffixString(string suffix)
{
return String.Concat(instance, suffix);
}
public override string ToString()
{
return instance;
}
public override bool TryConvert(ConvertBinder binder, out object result)
{
if (binder.Type != typeof(string))
return base.TryConvert(binder, out result);
result = instance;
return true;
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
var method = strType.GetMethod(binder.Name, args.Select(a => a.GetType()).ToArray());
if (method == null)
{
result = null;
return false;
}
result = method.Invoke(instance, args);
return true;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
var members = strType.GetMember(binder.Name);
if (members.Length > 0)
{
var member = members.Single();
switch (member.MemberType)
{
case MemberTypes.Property:
result = ((PropertyInfo)member).GetValue(instance, null);
return true;
break;
case MemberTypes.Field:
result = ((FieldInfo)member).GetValue(instance);
return true;
break;
}
}
return dynProperties.TryGetValue(binder.Name, out result);
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
var ret = base.TrySetMember(binder, value);
if (ret) return true;
dynProperties[binder.Name] = value;
return true;
}
}
If you want to be adventurous, you can define your own meta objects to handle the bindings. You could end up with reusable meta objects for different types and simplify your code immensely. I've been playing with this for a while and have this so far. It doesn't handle dynamically adding properties yet. I won't be working on this any further but I'll just leave it here for reference.
class DynamicString : DynamicObject
{
class DynamicStringMetaObject : DynamicMetaObject
{
public DynamicStringMetaObject(Expression parameter, object value)
: base(parameter, BindingRestrictions.Empty, value)
{
}
public override DynamicMetaObject BindConvert(ConvertBinder binder)
{
if (binder.Type == typeof(string))
{
var valueType = Value.GetType();
return new DynamicMetaObject(
Expression.MakeMemberAccess(
Expression.Convert(Expression, valueType),
valueType.GetProperty("Instance")),
BindingRestrictions.GetTypeRestriction(Expression, valueType));
}
return base.BindConvert(binder);
}
public override DynamicMetaObject BindGetMember(GetMemberBinder binder)
{
System.Diagnostics.Trace.WriteLine(String.Format("BindGetMember: {0}", binder.Name));
var valueType = Value.GetType();
var self = Expression.Convert(Expression, valueType);
var valueMembers = valueType.GetMember(binder.Name);
if (valueMembers.Length > 0)
{
return BindGetMember(self, valueMembers.Single());
}
var members = typeof(string).GetMember(binder.Name);
if (members.Length > 0)
{
var instance =
Expression.MakeMemberAccess(
self,
valueType.GetProperty("Instance"));
return BindGetMember(instance, members.Single());
}
return base.BindGetMember(binder);
}
private DynamicMetaObject BindGetMember(Expression instance, MemberInfo member)
{
return new DynamicMetaObject(
Expression.Convert(
Expression.MakeMemberAccess(instance, member),
typeof(object)),
BindingRestrictions.GetTypeRestriction(Expression, Value.GetType())
);
}
}
public string Instance { get; private set; }
public DynamicString(string instance)
{
Instance = instance;
}
public override DynamicMetaObject GetMetaObject(Expression parameter)
{
return new DynamicStringMetaObject(parameter, this);
}
public override string ToString()
{
return Instance;
}
public string GetPrefixString(string prefix)
{
return String.Concat(prefix, Instance);
}
public string GetSuffixString(string suffix)
{
return String.Concat(Instance, suffix);
}
}

Categories

Resources