Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to override get accessor of a dynamic object's property

Let's suppose I have the following class:

public class Person {
    public string Name { get; set; }
    public string Surname { get; set; }
    public string FullName {
        get {
            return Name + " " + Surname;
        }
    }
}

The following block:

Person person = new Person();
person.Name = "Matt";
person.Surname = "Smith";
return person.FullName;

would return Matt Smith.

Let's change our Person type to a dynamic ExpandoObject.

The code would look like this:

dynamic person = new ExpandoObject();
person.Name = "Matt";
person.Surname = "Smith";

But here's where I am stuck. How can I override the get accessor of a new FullName property?

I could achieve the same effect creating a new method:

person.GetFullName = (Func<string>)(() => {
      return person.Name + " " + person.Surname;
});

But this would end up with a method and not a property, therefore calling it like:

person.GetFullName();

EDIT

Please note that I do not want to know how to define or create a new dynamic property. I would like to know how to override or define a get accessor for a dynamic property.

I picture the code can be something like this:

person.FullName.get = (Func<string>)(() => {
     return person.Name + " " + person.Surname;
});

Then, invoked like this:

Console.WriteLine(person.FullName); //Prints out "Matt Smith"
like image 963
Matias Cicero Avatar asked Dec 20 '22 04:12

Matias Cicero


2 Answers

dynamic person = new GetterExpando();
person.Name = "Matt";
person.Surname = "Smith";
person.FullName = new GetterExpando.Getter(x => x.Name + " " + x.Surname);

Console.WriteLine(person.FullName);  // Matt Smith

// ...

public sealed class GetterExpando : DynamicObject
{
    private readonly Dictionary<string, object> _data = new Dictionary<string, object>();

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        _data[binder.Name] = value;
        return true;
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        object value;
        if (_data.TryGetValue(binder.Name, out value))
        {
            var getter = value as Getter;
            result = (getter == null) ? value : getter(this);
            return true;
        }
        return base.TryGetMember(binder, out result);
    }

    public delegate object Getter(dynamic target);
}
like image 97
LukeH Avatar answered Dec 21 '22 17:12

LukeH


public class SampleDynamicObject : DynamicObject
{
    Dictionary<string, Func<dynamic, object>> customFieldHandlers = new Dictionary<string, Func<dynamic, object>>();

    Dictionary<string, object> values = new Dictionary<string, object>();

    public void Get(string property, Func<dynamic, object> handler)
    {
        customFieldHandlers.Add(property, handler);
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        if (customFieldHandlers.ContainsKey(binder.Name))
        {
            result = customFieldHandlers[binder.Name](this);
            return true;
        }

        result = values[binder.Name];
        return true;
    }

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        values[binder.Name] = value;
        return true;
    }
}


dynamic sampleObject = new SampleDynamicObject();

        sampleObject.Get("FullName", (Func<dynamic, object>)((o) => 
        {
            dynamic obj = o;
            return o.Name + " " + o.Surname; 
        }));
like image 20
Vasil Akhmetov Avatar answered Dec 21 '22 18:12

Vasil Akhmetov