我知道创建动态对象的经典方法是从DynamicObject继承.但是,如果我已经有一个类,并且我希望将动态属性添加到其中,那么我就会陷入困境.
假设我有一个类ReactiveObject我希望使用DynamicObject为它添加动态属性.所以我这样做
public class MyReactiveObject : ReactiveObject, IDynamicMetaObjectProvider{
public DynamicMetaObject GetMetaObject(Expression parameter)
{
...
}
}
Run Code Online (Sandbox Code Playgroud)
我认为这样做的简单方法可能是创建一个DynamicObject实例并代理对它的调用.
public class MyDynamicObject : DynamicObject{}
public class MyReactiveObject : ReactiveObject, IDynamicMetaObjectProvider{
MyDynamicObject DynamicObject = new MyDynamicObject();
public DynamicMetaObject GetMetaObject(Expression parameter)
{
return this.DynamicObject.GetMetaObject(parameter);
}
}
Run Code Online (Sandbox Code Playgroud)
除了不起作用,因为返回的元对象对MyReactiveObject上的方法一无所知.有没有完全重新实现DynamicObject的简单方法.
另一种可能性是只使用这个库
https://github.com/remi/MetaObject
using System;
using System.Dynamic;
public class MyClass : Whatever, IDynamicMetaObjectProvider {
// This 1 line is *ALL* you need to add support for all of the DynamicObject methods
public DynamicMetaObject GetMetaObject(System.Linq.Expressions.Expression e)
{ return new MetaObject(e, this); }
// Now, if you want to handle dynamic method calls,
// you can implement TryInvokeMember, just like you would in DynamicObject!
public bool TryInvokeMember
(InvokeMemberBinder binder, object[] args, out object result) {
if (binder.Name.Contains("Cool")) {
result = "You called a method with Cool in the name!";
return true;
} else {
result = null;
return false;
}
}
}
Run Code Online (Sandbox Code Playgroud)
对于我的特定用例,它继承自 ReactiveUI.Reactive 对象并具有支持我生成的 INPC 的动态属性
using System;
using System.CodeDom;
using System.Collections.Generic;
using System.ComponentModel;
using System.Dynamic;
using System.Linq.Expressions;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using ReactiveUI;
namespace Weingartner.Lens
{
/// <summary>
/// An object you can add properties to at runtime which raises INPC events when those
/// properties are changed.
/// </summary>
[DataContract]
public class DynamicNotifyingObject : ReactiveObject, IDynamicMetaObjectProvider
{
#region Private Members
[DataMember]
private Dictionary<string, object> _DynamicProperties;
[DataMember]
private Dictionary<string, Type> _DynamicPropertyTypes;
#endregion Private Members
#region Constructor
public DynamicNotifyingObject() : this(new Tuple<string,Type>[] { }) { }
public DynamicNotifyingObject(IEnumerable<Tuple<string,Type>> propertyNames)
{
if (propertyNames == null)
{
throw new Exception("propertyNames is empty");
}
_DynamicProperties = new Dictionary<string, object>();
_DynamicPropertyTypes = new Dictionary<string, Type>();
foreach ( var prop in propertyNames )
{
AddProperty(prop.Item1, prop.Item2);
}
}
#endregion Constructor
public void AddProperty<T>( string propertyName, T initialValue )
{
_DynamicProperties.Add(propertyName, initialValue);
_DynamicPropertyTypes.Add(propertyName, typeof(T));
this.RaisePropertyChanged(propertyName);
}
/// <summary>
/// Set the property. Will throw an exception if the property does not exist.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="propertyName"></param>
/// <param name="raw"></param>
public void SetPropertyValue<T>(string propertyName, T raw)
{
if (!_DynamicProperties.ContainsKey(propertyName))
{
throw new ArgumentException(propertyName + " property does not exist on " + GetType().Name);
}
var converter = DynamicLens2INPC.CreateConverter<T>(raw.GetType(), _DynamicPropertyTypes[propertyName]);
var value = converter(raw);
if (!value.Equals(_DynamicProperties[propertyName]))
{
this.RaisePropertyChanging(propertyName);
_DynamicProperties[propertyName] = (object) value;
this.RaisePropertyChanged(propertyName);
}
}
/// <summary>
/// Get the property. Will throw an exception if the property does not exist.
/// </summary>
/// <param name="propertyName"></param>
/// <returns></returns>
public object GetPropertyValue(string propertyName)
{
if (!_DynamicProperties.ContainsKey(propertyName))
{
throw new ArgumentException(propertyName + " property does not exist " + GetType().Name);
}
return _DynamicProperties.ContainsKey(propertyName) ? _DynamicProperties[propertyName] : null;
}
public bool HasDynamicProperty(string propertyName) => _DynamicProperties.ContainsKey(propertyName);
DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression e) { return new MetaObject(e, this); }
/// <summary>
/// Support for MetaObject. See https://github.com/remi/MetaObject
/// </summary>
/// <param name="binder"></param>
/// <param name="result"></param>
/// <returns></returns>
public bool TryGetMember(GetMemberBinder binder, out object result)
{
if (HasDynamicProperty(binder.Name))
{
result = GetPropertyValue(binder.Name);
return true;
}
// This path will return any real properties on the object
result = null;
return false;
}
/// <summary>
/// Support for MetaObject. See https://github.com/remi/MetaObject
/// </summary>
/// <param name="binder"></param>
/// <param name="value"></param>
/// <returns></returns>
public bool TrySetMember(SetMemberBinder binder, object value)
{
if (HasDynamicProperty(binder.Name))
{
SetPropertyValue(binder.Name, value);
return true;
}
// This path will try to set any real properties on the object
return false;
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
710 次 |
| 最近记录: |