我在谈论与dynamic
类似的事情。 This没有回答我的问题,因此这个问题。我希望有一个类,我可以在运行时添加属性。它需要从类型object
继承。
我见过继承自DynamicObject
,但没有说明如何在运行时添加属性。我可以为此解决一些问题吗?
我有一个这样的课程:
public class SomeModel : DynamicObject {
public string SomeMandatoryProperty {get; set;}
}
我想在运行时将另一个类的所有属性添加到此类。所以例如。
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.
答案 0 :(得分:3)
我认为您正在寻找ExpandoObject:
ExpandoObject类使您能够 添加和删除其成员 运行时的实例,也可以设置 并获得这些成员的价值观。这个 class支持动态绑定 使您可以使用标准语法 比如sampleObject.sampleMember 比较复杂的语法 sampleObject.GetAttribute( “sampleMember”)。
dynamic manager;
manager = new ExpandoObject();
manager.Name = "Allison Brown";
manager.Age = 42;
manager.TeamSize = 10;
答案 1 :(得分:2)
您应该可以使用ExpandoObject
代替。 ExpandoObject
可以在运行时添加或删除成员,如果要转换为XML等,则可以提供非常好的支持。
来自MSDN文档:
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;
答案 2 :(得分:1)
您可以使用ExpandoObject
,因为您可以根据需要动态添加属性。但是,没有一种直接的方法可以轻松地使用来自另一个对象的值填充实例。您必须使用反射手动添加它。
你想编写一个包装器对象,你可以在仍然访问内部的同时添加属性吗?您可能需要考虑这种方式,您不必在两个不同的对象实例之间管理两个值的副本。我编写了一个测试类来包装字符串对象,以演示如何执行此操作(类似于ExpandoObject
的工作方式)。它应该让您了解如何为您的类型执行此操作。
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;
}
}
如果您想要冒险,可以定义自己的元对象来处理绑定。您最终可以获得不同类型的可重用元对象,并极大地简化您的代码。到目前为止,我已经玩了一段时间了。它还没有处理动态添加属性。我不会再进一步研究这个问题,但我会把它留在这里作为参考。
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);
}
}