Создание Expando Objects из базовых классов (чтобы использовались базовый конструктор, методы и свойства) и добавление в него других свойств и методов. - PullRequest
0 голосов
/ 20 марта 2020

Есть ли способ построить объект Expando из базового класса non-expandoObject?
Другими словами, я пытаюсь сделать что-то вроде:

// Instantiate my Expando object
dynamic myDynamicObject = new ExpandoObject();
// Add some base class to it - SomeBaseClass() can contain anything (Properties and methods)
myDynamicObject =  Add SomeBaseClass(); ???
// Add some other properties that are not in the base class
myDynamicObject.Name = "My Dynamic Object";
// Add some methods
myDynamicObject.SomeMethods = (Func<bool>)(() => {
   return true;
});

РЕДАКТИРОВАТЬ

Как предложено Мартином, мы можем создать Expando из другого объекта в соответствии с этим stackoverflow thread . Вот что они делают:

public static dynamic ToDynamic<T>(this T obj)
{
   IDictionary<string, object> expando = new ExpandoObject();

   foreach (var propertyInfo in typeof(T).GetProperties())
   {
       var currentValue = propertyInfo.GetValue(obj);
       expando.Add(propertyInfo.Name, currentValue);
   }
   return expando as ExpandoObject;
}

Однако этот пример заботится только о свойствах, но мне также нужны методы.

Итак, я попытался сделать что-то похожее для методов, но я не совсем понимаю, что я здесь делаю:

public static dynamic ToDynamic<T>(this T obj)
{
   IDictionary<string, object> expando = new ExpandoObject();

   MethodInfo[] info = typeof(T).GetMethods();

   foreach (var methodInfo in info)
   {
      if (methodInfo != null)
      {
          var currentMethod = methodInfo.GetMethodBody();
          expando.Add(methodInfo.Name, currentMethod);
      }
   }
   return expando as ExpandoObject;
}

Но затем, при попытке выполнить методы, я получаю это ошибка:

An unhandled exception of type 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' occurred in Unknown Module.

Дополнительная информация: невозможно вызвать тип без делегата

1 Ответ

1 голос
/ 20 марта 2020

На основании этого ответа , с небольшой заменой, чтобы не полагаться на дополнительный класс

public class Expando : DynamicObject
{
    public object Instance;
    Dictionary<string, dynamic> ExtraProperties = new Dictionary<string, dynamic>();

    public Expando(object instance)
    {
        Instance = instance;
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        try
        {
            result = Instance.GetType().GetProperty(binder.Name).GetValue(Instance,null);
            return true;
        }
        catch
        {
            if (ExtraProperties.Keys.Contains(binder.Name))
            {
                result = ExtraProperties[binder.Name];
                return true;
            }
        }

        result = null;
        return false;
    }

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        try
        {
            Instance.GetType().GetProperty(binder.Name).SetValue(Instance, value,null);
        }
        catch (Exception ex)
        {
            ExtraProperties[binder.Name] = value;
        }

        return true;
    }

    public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
    {
        try
        {
            result = Instance.GetType().GetMethod(binder.Name,args.Select(a=>a.GetType()).ToArray()).Invoke(Instance, args);
            return true;
        }
        catch
        { }

        result = null;
        return false;
    }

    public override string ToString()
    {
        return Instance.ToString();
    }

}

Если он взломает sh и сгорит на используемых вами классах, попробуйте исходный ответ (если дополнительная ссылка на класс не была обновлена, используйте https://github.com/RickStrahl/Westwind.Utilities/blob/master/Westwind.Utilities/Utilities/ReflectionUtils.cs

Обратите внимание, что тип возвращаемых членов не изменился. Это означает, что, например, если вы используете Expando для String, ваш Expando отвечает на Replace и PadLeft, но возвращаемым результатом является String, а не Expando, что может быть, а может и не быть тем, что вы хотите. если вам все еще это нужно. Кроме того, это решение не учитывает методы расширения, которые могут применяться к исходному классу.

...