在C#中保持控制台应用程序活着

时间:2016-08-03 22:02:16

标签: c# reflection console-application invoke

我刚创建了一个基本的控制台应用程序,它使用我的框架从文本文件中编译C#代码。

你运行它的方式是" SecureCodeBridge.exe File.txt",这个文本文件包含创建和显示工作正常的窗体的代码。

问题是因为我的应用程序是一个控制台应用程序,它会在调用文本文件中的方法后立即退出(表单显示一秒钟,并在控制台应用程序退出时消失...)

这是我的控制台应用程序的代码:

static void Main(string[] args)
{
    string entString = args[0];

    if(System.IO.File.Exists(entString))
    {
        string entContents = System.IO.File.ReadAllText(entString);
        SecureCode sC = new SecureCode(entContents);
        CompilerResults cR = sC.Compile();

        if(cR.Errors.Count > 0)
        {
            //Abort!
            foreach(CompilerError cE in cR.Errors)
            {
                Console.WriteLine(cE.ErrorText);
            }
        }
        else
        {
            sC.Run(cR);
        }
    }
}

这是我的框架用来编译和运行代码的代码:

public class SecureCode
{
    string code;
    public SecureCode(string source)
    {
        code = source;
    }

    public CompilerResults Compile()
    {
        Dictionary<string, string> providerOptions = new Dictionary<string, string>
        {
            {"CompilerVersion", "v3.5"}
        };
        CSharpCodeProvider provider = new CSharpCodeProvider(providerOptions);

        CompilerParameters compilerParams = new CompilerParameters
        {
            GenerateInMemory = true,
            GenerateExecutable = false
        };
        compilerParams.ReferencedAssemblies.Add("System.dll");
        compilerParams.ReferencedAssemblies.Add("System.Windows.Forms.dll");
        compilerParams.ReferencedAssemblies.Add("System.Drawing.dll");

        CompilerResults results = provider.CompileAssemblyFromSource(compilerParams, code);

        return results;
    }

    public void Run(CompilerResults results)
    {
        object o = results.CompiledAssembly.CreateInstance("Code.Class");
        MethodInfo mi = o.GetType().GetMethod("Main");
        mi.Invoke(o, null);
    }
}

在调用方法时,是否有某种方法可以使控制台应用程序保持活动状态? (例如,显示的表格)

1 个答案:

答案 0 :(得分:2)

Invoke将等待方法完成,BeginInvoke将异步运行,因此您的方法 完成(例如打开表单) )然后控制台应用程序退出。

如果你想等待应用程序/程序集你已经转出来退出,那么你可以将它作为一个进程运行(System.Diagnostics),你需要考虑如何获得你的将代码编译成可调用的格式:

var process = Process.Start(<options>);
process.WaitForExit();

另一个选择是坚持弱参考,我没有运行下面但它不应该很远。在垃圾收集器不再认为对象具有相关性之后,您将循环直到弱引用被清除:

WeakReference(weakRef = new WeakReference(results.CompiledAssembly.CreateInstance("Code.Class"));
MethodInfo mi = weakRef.Target.GetType().GetMethod("Main");
mi.Invoke(o, null);

// Wait until the application exists AND the Garbage Collector cleans it up
while (weakRef.IsAlive)
{
     Thread.Sleep(100);
}

我能想到的最后一个选项是在事件处理程序(比如OnExit或OnClose())中编译,然后通过反射与控制台应用程序中的等待机制进行连接,以便在收到回调时关闭。 From this post

//获取一个表示Click事件的EventInfo,然后获取     //处理事件的委托类型。     //     EventInfo evClick = tExForm.GetEvent(&#34; Click&#34;);     输入tDelegate = evClick.EventHandlerType;

// If you already have a method with the correct signature,
// you can simply get a MethodInfo for it. 
//
MethodInfo miHandler = 
    typeof(Example).GetMethod("LuckyHandler", 
        BindingFlags.NonPublic | BindingFlags.Instance);

// Create an instance of the delegate. Using the overloads
// of CreateDelegate that take MethodInfo is recommended.
Delegate d = Delegate.CreateDelegate(tDelegate, this, miHandler);

// Get the "add" accessor of the event and invoke it late-
// bound, passing in the delegate instance. This is equivalent
// to using the += operator in C#, or AddHandler in Visual
// Basic. The instance on which the "add" accessor is invoked
// is the form; the arguments must be passed as an array.
//
MethodInfo addHandler = evClick.GetAddMethod();
Object[] addHandlerArgs = { d };
addHandler.Invoke(exFormAsObj, addHandlerArgs);
祝你好运!