如何在运行时定义一个C#对象?

5

为了避免实体/属性/值数据库问题,我们将XML代码存储在单个关系型数据库字段中,但我不希望这破坏我的领域建模、DTO和仓储的好处。我无法绕过EAV/CR内容,但我可以选择如何存储它。问题是我该如何使用它?

如何在C#中将XML元数据转换为类/对象?

例如:

XML描述了我们有一个食谱,其中有各种属性,但通常相似,并且有一个或多个关于制作食物的属性。食物本身可以是任何东西,具有任何类型的疯狂制备方法。所有属性都会被搜索,并可能链接到现有的营养信息。

// <-- [Model validation annotation goes here for MVC2]
public class Pizza {
     public string kind  {get; set;}
     public string shape {get; set;}
     public string city  {get; set;}
     ...
}

在Action方法中:

makePizzaActionMethod (Pizza myPizza) {
    if (myPizza.isValid() ) {  // this is probably ModelState.isValid()...
        myRecipeRepository.Save( myPizza);
        return View("Saved");
    }
    else
        return View();
}

假设存储库不会特定于披萨。 - Zachary Scott
XML是否有模式?那么您可以使用该模式来生成代码。如果没有模式,则需要使用动态语言,而不是C#。 - John Saunders
我们可以为 XML 定义一个模式。食谱类一旦被创建后就不会改变,但可以根据需要动态地创建新的食谱类。每种客户类型大约有 15-20 种食谱类别,而我们有许多不同类型的客户,他们都喜欢美食。 - Zachary Scott
1
我不明白问题所在。你想最终得到什么样的对象?难道你不能将所有的XML加载到一个映射/树结构中吗?或者你想要它成为类型化的类?如果需要是类型化的类,那么显然你只需要将XML加载到你已经定义好的类型结构中。这似乎非常简单。你能再解释一下吗? - Noon Silk
我们的软件呈现了一个客户喜欢的工作流程。他们可以在软件中定义他们的小部件。我们对这些小部件并不了解很多,除了它们有很多字符串属性,由RegEx验证,并最终与实际物理属性(如价格、成本等)相关联。 - Zachary Scott
显示剩余9条评论
3个回答

9

您是否正在寻找ExpandoObject

它代表一个对象,其成员可以在运行时动态添加和删除。


哇,这是将知识应用于特定问题的好例子。我会让这个问题继续存在一段时间,但这个答案非常好。 - Zachary Scott
我个人觉得这很令人不安。但我想这不是辩论这个“事物”优点的地方。 - Noon Silk
欢迎来到动态C#的崭新世界。 - user24359

3

请查看System.Reflection.Emit命名空间。

您可以从AppDomain.CurrentDomain中使用AssemblyBuilder类开始。

AssemblyBuilder dynAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly("dynamic.dll",
                                                                            AssemblyBuilderAccess.RunAndSave);

从这里开始,您需要构建一个ModuleBuilder,然后才能构建TypeBuilder。

请查看AssmblyBuilder参考文档获取示例。

您可以保存生成的程序集,也可以仅在内存中使用它。但是请注意,您将会深入了解反射以使用这些动态类型。

编辑:

下面是如何遍历属性的示例:

AssemblyName aName = new AssemblyName("dynamic");
AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly(aName, AssemblyBuilderAccess.RunAndSave);
ModuleBuilder mb = ab.DefineDynamicModule("dynamic.dll");
TypeBuilder tb = mb.DefineType("Pizza");
//Define your type here based on the info in your xml
Type theType = tb.CreateType();

//instanciate your object
ConstructorInfo ctor = theType.GetConstructor(Type.EmptyTypes);
object inst = ctor.Invoke(new object[]{});

PropertyInfo[] pList = theType.GetProperties(BindingFlags.DeclaredOnly);
//iterate through all the properties of the instance 'inst' of your new Type
foreach(PropertyInfo pi in pList)
    Console.WriteLine(pi.GetValue(inst, null));

1
我仍然不明白这样的类如何被使用,因为代码并不知道额外的属性。 - John Saunders
你可以使用相关的Type类迭代新类型的属性。我将在上面添加一个示例。 - Grant Back

1

3
@cdiggins: -1:我无法想象XAML会如何有所帮助。如果您能帮助我想象一下,我会取消这个负评。 - John Saunders
添加了一些澄清。您可以使用XamlReader.Load()创建动态对象,这对Dr. Zim的情况是否有效?或者我有什么遗漏吗? - cdiggins
2
仍需要定义一个类来实现XamlReader - 例如Pizza类。 XAML不会为您创建类,但一旦类存在,它将从XML创建类的实例。 我认为Dr Zim的问题更多是围绕类的创建而不是从XML中读取。 - itowlson
Dr Zim:XAML 不仅限于 XAML 命名空间(我已成功使用 XamlReader 读取例如业务规则之类的内容),但您需要为不在 XAML 命名空间中的内容提供自己的命名空间映射。 - itowlson
@itowlson - 我给你的评论点了赞。你说得太好了:从XML迷你模式创建一个类。 - Zachary Scott
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接