如何在运行时将方法附加到动态创建的C#类型?

7
我被迫使用一种内部数据访问库,它实际上是将XML传递给存储过程,然后返回XML。我无法改变这种情况。我曾试图获得ActiveRecord的批准,但我的请求被拒绝了。然而,使用http://blog.bodurov.com/Post.aspx?postID=27提供的优秀代码,我添加了一个扩展方法到IEnumerable中,将不规则的XML转换成强类型对象,包括属性名称!

这样做:

dict["keyName1"]

变得

MyObject.keyName1

现在接口支持数据绑定了!非常酷!不过我想更进一步,我希望发出的对象也有Save()方法,这样我就可以模仿ActiveRecord模式,并为我的网络团队提供一个直观的对象层,从ASP.net中使用。
我该如何在Visual Studio中编写一个方法,在源代码中并将其在运行时附加到发出的对象上?我对编写程序集或IL不感兴趣(或没有资格)。我想用C#来实现这个目标。这是我第一个StackOverflow问题,我正在使用公司强制安装的IE6发布此问题,请温柔点。
2个回答

2
根据文章的内容,它为您创建了匿名类型,并且您正在使用它来获取值。如果是这种情况,那么没有简单的方法可以将方法添加到这些对象中。但是,如果XML结构在每次SP执行时都是相同的,为什么不创建一个具体类,该类具有您需要的所有属性,并使用XML自己填充这些对象的集合。这样,您就可以轻松地将所需的任何方法直接添加到类中...
编辑:根据我们在评论中的讨论,以下是一些想法:
在那里的代码中,当你正在构建类型时,你正在使用ModuleBuilder.DefineType。有一个重载的DefineType,它采用要扩展的类型。链接。因此,创建一个接口(它甚至不必有任何方法),并在动态构建类型时使用我链接给你的重载来扩展该接口。然后,在该接口上创建一个扩展方法,该方法执行Save()。
还有另一个可能感兴趣的重载,它采用要扩展的类型和接口: http://msdn.microsoft.com/en-us/library/f53tx4x8.aspx 编辑2:代码示例:
首先,创建一个接口:
public interface ISaveExtentable //I suck at naming stuff :-p
{

}

然后,在你喜欢的那个网站上的代码中,你会找到一个叫做GetTypeBuilder的方法。将其改为以下内容:

        private static TypeBuilder GetTypeBuilder(string typeSigniture)
        {
            AssemblyName an = new AssemblyName("TempAssembly" + typeSigniture);
            AssemblyBuilder assemblyBuilder =
                AppDomain.CurrentDomain.DefineDynamicAssembly(
                    an, AssemblyBuilderAccess.Run);
            ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");

            TypeBuilder tb = moduleBuilder.DefineType("TempType" + typeSigniture
                                , TypeAttributes.Public |
                                TypeAttributes.Class |
                                TypeAttributes.AutoClass |
                                TypeAttributes.AnsiClass |
                                TypeAttributes.BeforeFieldInit |
                                TypeAttributes.AutoLayout
                                , typeof(object), new Type[] {typeof(ISaveExtentable)});
            return tb;
        }

接着,在该接口上创建一个扩展方法来进行保存:

    public static class SaveExtendableExtensions
    {
          public static void Save(this ISaveExtentable ise)
          {
              //implement save functionality. 
          }
    }

由于类型是动态创建的,因此您很可能需要在Save方法中使用反射来获取所有属性。


如果 XML 结构每次存储过程执行时都相同。我会得到 <Instance><InstanceName>BRD 1245 RFW 3456</InstanceName><Attributes><ProjectName>项目名称!<ProjectName><OtherTags>等等</OtherTags></Attributes></Instance>,但每次属性都不同 :( - Chris McCall
是的,但我确定有一份可供选择的属性列表。将所有这些属性作为可空字段放入类中(如果它们是值类型),并仅填充您收到的那些属性。我认为您不需要使用一些疯狂的解决方案来动态构建类型... - BFree
XML是动态生成的,我不想为每个排列组合维护一个具体类库。 - Chris McCall
我喜欢这个编辑。我不是在要求代码,但您是否介意在您的答案中提供一些示例代码以更好地勾勒出这个想法? - Chris McCall
很抱歉,您在这种情况下使用TypeBuilder会引入内存泄漏。以这种方式生成的程序集直到整个应用程序域被卸载(即应用程序关闭)之前都不会从当前应用程序域中卸载。 - Denis Vuyka
一旦程序集被加载到应用程序域中,除非拆除应用程序域,否则永远无法卸载它。这不是内存泄漏,而是设计如此。因此,如果您想动态创建类型,这就是方法。没有其他方式。 - BFree

1

我认为这被称为mix-ins,它在.NET中不是直接或容易地可用的。然而,据我所知,这是LinFu框架设计的主要原因之一。


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