csharpprovider.cs

来自「动态执行csharp代码」· CS 代码 · 共 328 行

CS
328
字号
using System;
using System.Collections.Generic;
using System.Text;
using System.CodeDom.Compiler;
using System.Reflection;
using Microsoft.CSharp;
using Microsoft.VisualBasic;
using Compiler.Dynamic.Text;

namespace Compiler.Dynamic
{
    public class CSharpProvider : IDisposable
    {
        #region Private fields
        private CSharpCodeProvider _CSharpCodePrivoder;
        private CompilerParameters _CompilerParameters = new CompilerParameters();
        private CompilerResults _Clr;
        private string _Code;
        private DateTime _LstFileTime = DateTime.Parse("1900-1-1");
        private AppDomain _AppDomain;
        private string _AssemblyFileName = "DynamicTemp.dll";
        private bool _RemoveAssemblyFile;
        private Encoding _SourceCodeFileEncoding = Encoding.Default;
        private DotNetReferences _DotNetReferences = new DotNetReferences();

        #endregion

        #region Public Properties

        /// <summary>
        /// Manage the references
        /// </summary>
        public DotNetReferences References
        {
            get
            {
                return _DotNetReferences;
            }
        }

        /// <summary>
        /// Get or set the output assembly file name for the dynamic source code
        /// </summary>
        public string AssemblyFileName
        {
            get
            {
                return _AssemblyFileName;
            }

            set
            {
                _AssemblyFileName = value;
            }
        }

        /// <summary>
        /// The compilier parameters
        /// </summary>
        public CompilerParameters CompilerParameters
        {
            get
            {
                return _CompilerParameters;
            }
        }

        /// <summary>
        /// If this property set to true,
        /// When the object intance from this class dispose,
        /// the assembly File that is compiled will be deleted.
        /// </summary>
        public bool RemoveAssemblyFile
        {
            get
            {
                return _RemoveAssemblyFile;
            }

            set
            {
                _RemoveAssemblyFile = value;
            }
        }

        /// <summary>
        /// Get or set the encoding of source code file 
        /// </summary>
        public Encoding SourceCodeFileEncoding
        {
            get
            {
                return _SourceCodeFileEncoding;
            }

            set
            {
                _SourceCodeFileEncoding = value;
            }
        }

        #endregion

        #region Private methods

        private void LoadReference(string code)
        {
            foreach (string reference in References.GetReferences())
            {
                if (reference != null)
                {
                    if (_CompilerParameters.ReferencedAssemblies.IndexOf(reference) < 0)
                    {
                        _CompilerParameters.ReferencedAssemblies.Add(reference);
                    }
                }
            }

            foreach (string nameSpace in ReferenceInCode.GetNameSpacesInSourceCode(code))
            {
                string referenceDll = References[nameSpace];
                if (referenceDll != null)
                {
                    if (_CompilerParameters.ReferencedAssemblies.IndexOf(referenceDll) < 0)
                    {
                        _CompilerParameters.ReferencedAssemblies.Add(referenceDll);
                    }
                }
            }
        }


        /// <summary>
        /// Create the instance named or inherited by typeFullName
        /// </summary>
        /// <param name="code">code string or source code file name</param>
        /// <param name="typeFullName">the full name of type</param>
        /// <param name="fromFile">from file or from code string</param>
        /// <returns>instance object</returns>
        /// <remarks>If the type named or inherited by typefullname does not exits, return null</remarks>
        private object InnerCreateInstance(string code, string typeFullName, bool fromFile)
        {
            bool reCompile = false;

            if (fromFile)
            {
                reCompile = CompileFromFile(code);
            }
            else
            {
                reCompile = Compile(code);
            }

            if (reCompile)
            {
                AppDomainSetup appDomainSetup;

                appDomainSetup = new AppDomainSetup();
                appDomainSetup.LoaderOptimization = LoaderOptimization.SingleDomain;
                appDomainSetup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
                appDomainSetup.ShadowCopyDirectories = appDomainSetup.ApplicationBase;
                appDomainSetup.ShadowCopyFiles = "true";
                _AppDomain = AppDomain.CreateDomain(AssemblyFileName, null, appDomainSetup);
            }

            RemoteAccess.RemoteLoader remoteLoader = (RemoteAccess.RemoteLoader)_AppDomain.CreateInstance("Compiler.Dynamic", "RemoteAccess.RemoteLoader").Unwrap();
            return remoteLoader.Create(AssemblyFileName, typeFullName, null);
        }

        #endregion

        #region Constructor

        public CSharpProvider()
        {
        }

        ~CSharpProvider()
        {
            try
            {
                Dispose();
            }
            catch
            {
            }
        }


        #endregion

        #region Public methods

        /// <summary>
        /// Compiler From source code file
        /// </summary>
        /// <param name="sourceCodeFileName">The file name of source code</param>
        /// <returns></returns>
        public bool CompileFromFile(string sourceCodeFileName)
        {
            DateTime fileTime = System.IO.File.GetLastWriteTime(sourceCodeFileName);

            if (_LstFileTime == fileTime)
            {
                return false;
            }

            _LstFileTime = fileTime;

            string code = File.ReadFileToString(sourceCodeFileName, SourceCodeFileEncoding);

            bool removeAssemblyFile = RemoveAssemblyFile;
            RemoveAssemblyFile = true;
            Dispose();
            RemoveAssemblyFile = removeAssemblyFile;

            _CSharpCodePrivoder = new CSharpCodeProvider();

            LoadReference(code);
            _Code = code;
            _CompilerParameters.GenerateInMemory = false;
            _CompilerParameters.OutputAssembly = AssemblyFileName;

            string[] files = new string[1];
            files[0] = sourceCodeFileName;

            _Clr = _CSharpCodePrivoder.CompileAssemblyFromFile(_CompilerParameters, files);

            if (_Clr.Errors.HasErrors)
            {
                throw new CompilerException(code, _Clr.Errors);
            }

            return true;
        }

        public bool Compile(string code)
        {
            if (code == _Code)
            {
                return false;
            }

            bool removeAssemblyFile = RemoveAssemblyFile;
            RemoveAssemblyFile = true;
            Dispose();
            RemoveAssemblyFile = removeAssemblyFile;

            _Code = code;
            _CSharpCodePrivoder = new CSharpCodeProvider();

            LoadReference(code);

            _CompilerParameters.GenerateInMemory = false;
            _CompilerParameters.OutputAssembly = AssemblyFileName;

            _Clr = _CSharpCodePrivoder.CompileAssemblyFromSource(_CompilerParameters, code);

            if (_Clr.Errors.HasErrors)
            {
                throw new CompilerException(code, _Clr.Errors);
            }

            return true;
        }



        /// <summary>
        /// Create the instance named or inherited by typeFullName
        /// </summary>
        /// <param name="code">source code string</param>
        /// <param name="typeFullName">the full name of type</param>
        /// <returns>instance object</returns>
        /// <remarks>If the type named or inherited by typefullname does not exits, return null</remarks>
        public object CreateInstance(string code, string typeFullName)
        {
            return InnerCreateInstance(code, typeFullName, false);
        }

        /// <summary>
        /// Create the instance named or inherited by typeFullName
        /// </summary>
        /// <param name="fileName">source code file</param>
        /// <param name="typeFullName">the full name of type</param>
        /// <returns>instance object</returns>
        /// <remarks>If the type named or inherited by typefullname does not exits, return null</remarks>
        public object CreateInstanceFromFile(string fileName, string typeFullName)
        {
            return InnerCreateInstance(fileName, typeFullName, true);
        }



        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            if (_AppDomain != null)
            {
                AppDomain.Unload(_AppDomain);
                _AppDomain = null;
            }

            _Clr = null;

            GC.Collect();

            if (RemoveAssemblyFile)
            {
                if (System.IO.File.Exists(AssemblyFileName))
                {
                    System.IO.File.Delete(AssemblyFileName);
                }

                if (System.IO.File.Exists(System.IO.Path.GetFileName(AssemblyFileName) + ".pdb"))
                {
                    System.IO.File.Delete(System.IO.Path.GetFileName(AssemblyFileName) + ".pdb");
                }
            }
        }

        #endregion
    }
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?