sbe*_*rli 31 .net c# dynamic .net-4.0
我正在探索.NET 4.0中的DynamicObject模型.应用程序是通过某种text/xml文件描述对象的应用程序,程序必须在读取该文件时创建对象.
使用DynamicObject,我们可以轻松添加成员,因为我们知道成员的名称是先验的.但是,如果我们甚至不知道要添加的成员的名称呢?有没有办法让这种动态变化?
例如,假设我需要使用成员'Property1','Property2'创建一个对象,使用'PropertyA'创建另一个对象,并使用text/XML文件描述'PropertyB'.如何根据此信息动态创建对象?
更新 我从这篇文章中得到了一些想法:http://www.codeproject.com/KB/cs/dynamicincsharp.aspx
这个实现允许我做类似以下的事情:
dynamic d = new PFDynamicChannel();
PFCouplings c = ((PFChannel)d).Coupling;
d.NewProperty = "X";
Run Code Online (Sandbox Code Playgroud)
我不想使用字典的原因是使用TryGetMember和TrySetMember方法,我可以覆盖,我可以在其中引发对程序至关重要的事件.
这样,我可以继承基类(PFChannel),但我也可以动态添加成员.但是,我的问题是我不会知道新的属性名称,直到运行时.而且,我实际上并不认为动态对象允许我动态添加新属性.如果是这种情况,我如何利用ExpandoObject来提供这种能力呢?
Jon*_*eet 46
如果你只需要这样做,你应该看看ExpandoObject.如果你需要这样做并仍然使用DynamicObject,你将需要编写代码来记住属性值,基本上......你可能会使用嵌入式代码ExpandoObject.
之后我不清楚你想用这个对象做什么 - 你确定你需要动态打字吗?将一个Dictionary<string, object>实际上是更糟?这取决于以后基本上会消耗该对象的内容.
Tha*_*dis 34
根据这个:动态地向ExpandoObject添加属性和方法!,
...您可以使用expando对象作为值持有者,并在想要添加动态命名属性时将其强制转换为IDictionary <string,object>.
例
dynamic myobject = new ExpandoObject();
IDictionary<string, object> myUnderlyingObject = myobject;
myUnderlyingObject.Add("IsDynamic", true); // Adding dynamically named property
Console.WriteLine(myobject.IsDynamic); // Accessing the property the usual way
Run Code Online (Sandbox Code Playgroud)
这已经过测试,并将在控制台屏幕上打印出"true".
当然,在您的情况下,您的底层对象必须从另一个类继承,这个示例只是为了让您了解潜在的自定义实现.
也许在类实现中包含一个expando对象,并将调用重定向到tryget和tryset到类中expando对象的实例?
UPDATE
如果您的基类派生自DynamicObject(意味着您可以覆盖所有TrySet/Get/Invoke方法),那么您也可以在内部使用字典.在try get/set覆盖中,您可以执行任何您想要的事件,并将设置委托给内部字典.
要添加新属性(或删除现有属性),您可以覆盖TryInvoke.例如,当mothod名称是"AddProperty"并且有一个类型为string的参数时,您将在字典中添加一个带有参数名称的新项.类似地,您将动态定义"RemoveProperty"等.您甚至不需要expando对象.
class MyBaseClass: DynamicObject
{
// usefull functionality
}
class MyClass: MyBaseClass
{
Dictionary<string, object> dynamicProperties = new Dictionary<string, object>();
override bool TryGetMember(...)
{
// read the value of the requested property from the dictionary
// fire any events and return
}
override bool TrySetMember(...)
{
// set the value of the requested property to the dictionary
// if the property does not exist,
// add it to the dictionary (compile time dynamic property naming)
// fire any events
}
override bool TryInvoke(...)
{
// check what method is requested to be invoked
// is it "AddProperty"??
// if yes, check if the first argument is a string
// if yes, add a new property to the dictionary
// with the name given in the first argument (runtime dynamic property naming)
// if there is also a second argument of type object,
// set the new property's value to that object.
// if the method to be invoked is "RemoveProperty"
// and the first argument is a string,
// remove from the Dictionary the property
// with the name given in the first argument.
// fire any events
}
}
// USAGE
static class Program
{
public static void Main()
{
dynamic myObject = new MyClass();
myObject.FirstName = "John"; // compile time naming - TrySetMember
Console.WriteLine(myObject.FirstName); // TryGetMember
myObject.AddProperty("Salary"); // runtime naming (try invoke "AddProperty" with argument "Salary")
myObject.Salary = 35000m;
Console.WriteLine(myObject.Salary); // TryGetMember
myObject.AddProperty("DateOfBirth", new DateTime(1980,23,11)); // runtime naming (try invoke "AddProperty" with fisrt argument "DateOfBirth" and second argument the desired value)
Console.WriteLine(myObject.DateOfBirth); // TryGetMember
myObject.RemoveProperty("FirstName"); // runtime naming (try invoke "RemoveProperty" with argument "FirstName")
Console.WriteLine(myObject.FirstName); // Should print out empty string (or throw, depending on the desired bahavior) because the "FirstName" property has been removed from the internal dictionary.
}
}
Run Code Online (Sandbox Code Playgroud)
当然,正如我所说的那样,只有你的基类派生自DynamicObject时才有效.
在这种情况下,我不确定您是否要使用动态对象.
c#中的dynamic允许你做以下事情:
dynamic something = GetUnknownObject();
something.aPropertyThatShouldBeThere = true;
Run Code Online (Sandbox Code Playgroud)
如果您使用ExpandoObject,您可以:
var exp = GetMyExpandoObject();
exp.APropertyThatDidntExist = "something";
Run Code Online (Sandbox Code Playgroud)
这两个都允许您使用propertyname,就好像它在编译时实际存在一样.在您的情况下,您根本不需要使用此语法,因此我不确定它会给您带来任何好处.相反,为什么不使用a Dictionary<string, object>,和:
var props = new Dictionary<string, object>();
foreach( var someDefinintion in aFile)
{
props[ someDefinition.Name] = someDefinition.value;
}
Run Code Online (Sandbox Code Playgroud)
因为a Dictionary<string,object>基本上是一个expando对象 - 但它支持不同的语法.是的,我正在简化 - 但如果你不是从其他代码或通过绑定/等使用它,那么这基本上是正确的.
小智 7
与 Thanasis Ioannidis 关于变体“如果您的基类派生自 DynamicObject”的答案相关,有一种更简单的方法,只需在“MyClass”类中添加方法 AddProperty,如下所示:
class MyClass: MyBaseClass
{
Dictionary<string, object> dynamicProperties = new Dictionary<string, object>();
public void AddProperty(string key, object value){
dynamicProperties[key] = value;
}
Run Code Online (Sandbox Code Playgroud)
然后你可以使用
dynamic myObject = new MyClass();
myObject.AddProperty("DateOfBirth", new DateTime(1980,23,11));
Run Code Online (Sandbox Code Playgroud)
您不需要对“TryInvoke”进行任何覆盖。
| 归档时间: |
|
| 查看次数: |
82968 次 |
| 最近记录: |