CodeDom隐式创建资源检索语句;导致无法卸载的代码 [英] CodeDom implicitly creating resource retrieval statements; causes unloadable code

查看:76
本文介绍了CodeDom隐式创建资源检索语句;导致无法卸载的代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述


我使用标准的C#WinForms设计器让用户创建对话框.当用户想要显示对话框时,我可以使用我自己的CodeDomDesignerLoader子类(称为FormEditorCodeDomDesignerLoader)将其编译为Assembly文件(DLL).


I’m using a standard C# WinForms Designer to let the user create a Dialog box.  When the user wants to show the dialog box, I compile it into an Assembly file (a DLL) using my own subclass of CodeDomDesignerLoader, which I call FormEditorCodeDomDesignerLoader.

在FormEditorCodeDomDesignerLoader中创建CodeCompileUnit的代码如下:

The code that creates the CodeCompileUnit in the FormEditorCodeDomDesignerLoader looks like this:

      受保护的重写CodeCompileUnit Parse()
       {
           DesignSurface ds = new DesignSurface();
           ds.BeginLoad(typeof(Form));
           IDesignerHost idh =(IDesignerHost)ds.GetService(typeof(IDesignerHost));

        protected override CodeCompileUnit Parse()
        {
            DesignSurface ds = new DesignSurface();
            ds.BeginLoad(typeof (Form));
            IDesignerHost idh = (IDesignerHost)ds.GetService(typeof(IDesignerHost));

         返回CreateCCU(idh);
       }

           return CreateCCU (idh);
        }

      私有CodeCompileUnit CreateCCU(IDesignerHost idh)
       {
           idh.RootComponent.Site.Name ="Form1";

        private CodeCompileUnit CreateCCU (IDesignerHost idh)
        {
            idh.RootComponent.Site.Name = "Form1";

           cg = new FormEditorCodeGen();
           CodeCompileUnit ccu = cg.GetCodeCompileUnit(idh);

            cg = new FormEditorCodeGen();
            CodeCompileUnit ccu = cg.GetCodeCompileUnit(idh);

           AssemblyName []名称= Assembly.GetExecutingAssembly().GetReferencedAssemblies();
           for(int i = 0; i< names.Length; i ++)
           {
                            程序集程序集= Assembly.Load(names [i]);
                             ccu.ReferencedAssemblies.Add(assembly.Location);
           }

            AssemblyName[] names = Assembly.GetExecutingAssembly().GetReferencedAssemblies();
            for (int i = 0; i < names.Length; i++)
            {
                Assembly assembly = Assembly.Load(names[i]);
                ccu.ReferencedAssemblies.Add(assembly.Location);
            }

           codeCompileUnit = ccu;
           return ccu;
       }

            codeCompileUnit = ccu;
            return ccu;
        }

     内部类FormEditorCodeGen
      {
       私有CodeCompileUnit codeCompileUnit;
       私有CodeNamespace ns;
       私有CodeTypeDeclaration myDesignerClass = new CodeTypeDeclaration();
       私有CodeMemberMethod initializeComponent = new CodeMemberMethod();
       私人IDesignerHost主机;
       私有IComponent根;

       internal class FormEditorCodeGen
       {
         private CodeCompileUnit codeCompileUnit;
         private CodeNamespace ns;
         private CodeTypeDeclaration myDesignerClass = new CodeTypeDeclaration();
         private CodeMemberMethod initializeComponent = new CodeMemberMethod();
         private IDesignerHost host;
         private IComponent root;

        ///< summary>
        ///此函数生成默认的CodeCompileUnit模板
       ///</summary>
       公共CodeCompileUnit GetCodeCompileUnit(IDesignerHost主机)
       {
           this.host =主机;
           IDesignerHost idh =(IDesignerHost)this.host.GetService(typeof(IDesignerHost));
           root = idh.RootComponent;
          哈希表名称表=新的哈希表(idh.Container.Components.Count);

         /// <summary>
         /// This function generates the default CodeCompileUnit template
        /// </summary>
         public CodeCompileUnit GetCodeCompileUnit(IDesignerHost host)
        {
            this.host = host;
            IDesignerHost idh = (IDesignerHost)this.host.GetService(typeof(IDesignerHost));
            root = idh.RootComponent;
            Hashtable nametable = new Hashtable(idh.Container.Components.Count);

           ns = new CodeNamespace("YetiFormEditor");
           myDesignerClass = new CodeTypeDeclaration();
           initializeComponent = new CodeMemberMethod();

            ns = new CodeNamespace("YetiFormEditor");
            myDesignerClass = new CodeTypeDeclaration();
            initializeComponent = new CodeMemberMethod();

           CodeCompileUnit代码=新的CodeCompileUnit();

            CodeCompileUnit code = new CodeCompileUnit();

           //导入
           ns.Imports.Add(新的CodeNamespaceImport(系统")));
           ns.Imports.Add(新的CodeNamespaceImport("System.ComponentModel"));
           ns.Imports.Add(新的CodeNamespaceImport("System.Windows.Forms"));
           ns.Imports.Add(新的CodeNamespaceImport("AGI.FormEditor"));
           code.Namespaces.Add(ns);
           myDesignerClass =新的CodeTypeDeclaration(root.Site.Name);
           myDesignerClass.BaseTypes.Add(typeof(Form).FullName);

            // Imports
            ns.Imports.Add(new CodeNamespaceImport("System"));
            ns.Imports.Add(new CodeNamespaceImport("System.ComponentModel"));
            ns.Imports.Add(new CodeNamespaceImport("System.Windows.Forms"));
            ns.Imports.Add(new CodeNamespaceImport("AGI.FormEditor"));
            code.Namespaces.Add(ns);
            myDesignerClass = new CodeTypeDeclaration(root.Site.Name);
            myDesignerClass.BaseTypes.Add(typeof(Form).FullName);

           IDesignerSerializationManager管理器=
              nbsp; bsp     host.GetService(typeof(IDesignerSerializationManager))作为IDesignerSerializationManager;

            IDesignerSerializationManager manager =
                              host.GetService(typeof(IDesignerSerializationManager)) as IDesignerSerializationManager;

           ns.Types.Add(myDesignerClass);

            ns.Types.Add(myDesignerClass);

           //构造函数
           CodeConstructor con =新的CodeConstructor();

            // Constructor
            CodeConstructor con = new CodeConstructor();

           con.Attributes = MemberAttributes.Public;
           con.Statements.Add(new CodeMethodInvokeExpression(
          new CodeMethodReferenceExpression(new CodeThisReferenceExpression(),"InitializeComponent")));
           myDesignerClass.Members.Add(con);

            con.Attributes = MemberAttributes.Public;
            con.Statements.Add(new CodeMethodInvokeExpression(
           new CodeMethodReferenceExpression(new CodeThisReferenceExpression(), "InitializeComponent")));
            myDesignerClass.Members.Add(con);

           //InitializeComponent
           initializeComponent.Name ="InitializeComponent";
           initializeComponent.Attributes = MemberAttributes.Private;
           initializeComponent.ReturnType =新的CodeTypeReference(typeof(void));
           myDesignerClass.Members.Add(ini​​tializeComponent);
           codeCompileUnit =代码;
          返回codeCompileUnit;
 }
      }//班级

            // InitializeComponent
            initializeComponent.Name = "InitializeComponent";
            initializeComponent.Attributes = MemberAttributes.Private;
            initializeComponent.ReturnType = new CodeTypeReference(typeof(void));
            myDesignerClass.Members.Add(initializeComponent);
            codeCompileUnit = code;
            return codeCompileUnit;
 }
       }// class

 


接受CodeCompileUnit并将其转换为Assembly(DLL)文件的代码如下:


The code that takes the CodeCompileUnit and turns it into an Assembly (DLL) file looks like this:

      公共布尔构建(字符串dllFileName)
       {
             Flush();

        public bool Build (string dllFileName)
        {
               Flush();

                        //我们需要收集编译器将使用的参数.
             CompilerParameters cp = new CompilerParameters();
             AssemblyName [] assemblyNames = Assembly.GetEntryAssembly().GetReferencedAssemblies();

               // We need to collect the parameters that our compiler will use.
               CompilerParameters cp = new CompilerParameters();
               AssemblyName[] assemblyNames = Assembly.GetEntryAssembly().GetReferencedAssemblies();

                        foreach(assemblyNames中的AssemblyName和)
             {
]装配装配= Assembly.Load(an);
] cp.ReferencedAssemblies.Add(assembly.Location);
             }

               foreach (AssemblyName an in assemblyNames)
               {
                      Assembly assembly = Assembly.Load(an);
                      cp.ReferencedAssemblies.Add(assembly.Location);
               }

                        cp.GenerateExecutable = false;  //仅对包含入口点的代码设置为true
             cp.OutputAssembly = dllFileName;

               cp.GenerateExecutable = false;  // only set to true for code that contains an entry point
               cp.OutputAssembly = dllFileName;

//记住我们的主类不是Form,而是Form1!
                                      字符串mainClass ="YetiFormEditor.Form1";
                                       cp.MainClass = mainClass;

              // Remember our main class is not Form, but Form1!
             string mainClass = "YetiFormEditor.Form1";
             cp.MainClass = mainClass;

            CSharpCodeProvider cc =新的CSharpCodeProvider();
                                       CompilerResults cr = cc.CompileAssemblyFromDom(cp,codeCompileUnit);

             CSharpCodeProvider cc = new CSharpCodeProvider();
             CompilerResults cr = cc.CompileAssemblyFromDom(cp, codeCompileUnit);

return!cr.Errors.HasErrors;
       }

              return !cr.Errors.HasErrors;
        }


这是我的问题:


Here’s my problem:

每当设计对话框中的任何控件的字符串属性长于200个字符时,生成的DLL中的代码就会包含一个隐式调用,以从DLL程序集的资源中检索此字符串. 并且DLL程序集没有任何字符串资源!尝试调用dllAssembly.CreateInstance("YetiFormEditor.Form1")时,这会导致异常.如果字符串属性为200个字符或更短,则此异常 不会发生,并且对话框创建成功.

Whenever any of the controls within the Dialog box being designed has a string Property that’s longer than 200 characters, the code in the generated DLL contains an implicit call to retrieve this string from the DLL Assembly’s resources – and the DLL Assembly doesn’t HAVE any string resources!  This causes an exception when attempting to call dllAssembly.CreateInstance (“YetiFormEditor.Form1”);.  If the string Property is 200 characters or shorter, this exception does not occur and the dialog box gets created successfully.

我查看了CodeCompileUnit中的C#代码(通过CSharpCodeProvider.GenerateCodeFromCompileUnit()).如果字符串属性为200个字符或更少,我将看到以下内容:

I looked at the C# code in the CodeCompileUnit (via CSharpCodeProvider.GenerateCodeFromCompileUnit() ).  If the string Property is 200 characters or less I’ll see this:

this.comboBox1.MyProperty ="012345678901234567890123456789012345678901234567890123456789012345678901234567890" +
" 12345678901234567890123456789012345678901234567890123456789012345678901234567890" +
" 123456789012345678901234567890123456789'';

this.comboBox1.MyProperty = "012345678901234567890123456789012345678901234567890123456789012345678901234567890" +
"12345678901234567890123456789012345678901234567890123456789012345678901234567890" +
"123456789012345678901234567890123456789";

…但是如果字符串属性超过200个字符,我会看到以下内容:

… but if the string Property is more than 200 characters I’ll see this:

this.comboBox1.MyProperty = resources.GetString("comboBox1.MyProperty");

this.comboBox1.MyProperty = resources.GetString("comboBox1.MyProperty");


考虑到必须超过200个字符的通用属性(例如,图像属性,多行文本编辑的内容等),我无法相信没有其他人遇到过此问题.所以:


I cannot believe no one else has run into this issue, considering how commonplace Properties longer than 200 characters must be (e.g. Image properties, the contents of a multi-line text edit, etc.).  So:

是否有一种方法可以使CodeCompileUnit(或CompileAssemblyFromDom()调用)显式包括此生成的代码所依赖的字符串资源,或者有一种方法可以使CodeCompileUnit/CompileAssemblyFromDom()生成长字符串的代码 不需要资源?

Is there a way to either make the CodeCompileUnit (or the CompileAssemblyFromDom() call) explicitly include the string resources this generated code depends on, or a way to make the CodeCompileUnit/CompileAssemblyFromDom() generate code for long strings that doesn’t require resources?


谢谢!

推荐答案

我将帮助您将主题移到CLR论坛.您将在那里获得更多有用的建议.

I'll help you moving your thread into CLR forum. You will get more helpful suggestions there.

最好的问候


这篇关于CodeDom隐式创建资源检索语句;导致无法卸载的代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆