#include <iostream>
#include <string>
using namespace std;
int main()
{
cout << "Enter the number: ";
int number;
cin >> number;
cout << "Enter names: ";
string names;
// USE peek() TO SOLVE IT! ;)
if (cin.peek() == '\n') {
cin.ignore(1 /*numeric_limits<streamsize>::max()*/, '\n');
}
getline(cin, names);
return 0;
}
Просто загляните вперед, используя cin.peek()
, и посмотрите, остается ли '\n'
во внутреннем буфере cin
. Если да: проигнорируйте его (в основном пропустите его)
Выгрузка сборки не поддерживается. Некоторую информацию о причинах можно найти здесь . Некоторую информацию об использовании AppDomain можно найти здесь .
Вы также можете найти эту запись в блоге полезной: Использование AppDomain для загрузки и выгрузки динамических сборок. Он предоставляет пример кода, демонстрирующий, как создать домен приложения, загрузить в него (динамическую) сборку, выполнить некоторую работу в новом домене приложения, а затем выгрузить его.
Изменить: исправлена ссылка, как указано в комментариях ниже.
Вы можете дождаться .NET 4.0? С его помощью вы можете использовать деревья выражений и DLR для динамической генерации кода без проблемы потери памяти при генерации кода.
Другой вариант - использовать .NET 3.5 с динамическим языком, таким как IronPython.
РЕДАКТИРОВАТЬ: Пример дерева выражений
1251] http://www.infoq.com/articles/expression-compiler
Думаю, у меня есть рабочее решение. Спасибо всем за то, что указали мне правильное направление (надеюсь).
Сборки нельзя выгружать напрямую, но можно использовать домены приложений. Я создал вспомогательную библиотеку, которая загружается в новый домен приложения и может скомпилировать новую сборку из кода. Вот как выглядит класс в этой вспомогательной библиотеке:
public class CompilerRunner : MarshalByRefObject
{
private Assembly assembly = null;
public void PrintDomain()
{
Console.WriteLine("Object is executing in AppDomain \"{0}\"",
AppDomain.CurrentDomain.FriendlyName);
}
public bool Compile(string code)
{
CSharpCodeProvider codeProvider = new CSharpCodeProvider();
CompilerParameters parameters = new CompilerParameters();
parameters.GenerateInMemory = true;
parameters.GenerateExecutable = false;
parameters.ReferencedAssemblies.Add("system.dll");
CompilerResults results = codeProvider.CompileAssemblyFromSource(parameters, code);
if (!results.Errors.HasErrors)
{
this.assembly = results.CompiledAssembly;
}
else
{
this.assembly = null;
}
return this.assembly != null;
}
public object Run(string typeName, string methodName, object[] args)
{
Type type = this.assembly.GetType(typeName);
return type.InvokeMember(methodName, BindingFlags.InvokeMethod, null, assembly, args);
}
}
Он очень простой, но его было достаточно для тестирования. PrintDomain нужен, чтобы убедиться, что он действительно живет в моем новом домене приложений. Компиляция берет некоторый исходный код и пытается создать сборку. Run позволяет нам тестировать выполнение статических методов из данного исходного кода.
Вот как я использую вспомогательную библиотеку:
static void CreateCompileAndRun()
{
AppDomain domain = AppDomain.CreateDomain("MyDomain");
CompilerRunner cr = (CompilerRunner)domain.CreateInstanceFromAndUnwrap("CompilerRunner.dll", "AppDomainCompiler.CompilerRunner");
cr.Compile("public class Hello { public static string Say() { return \"hello\"; } }");
string result = (string)cr.Run("Hello", "Say", new object[0]);
AppDomain.Unload(domain);
}
Она в основном создает домен, создает экземпляр моего вспомогательного класса (CompilerRunner), использует его для компиляции нового Assembly (скрытая), запускает некоторый код из этой новой сборки, а затем выгружает домен, чтобы освободить память.
Вы заметите использование MarshalByRefObject и CreateInstanceFromAndUnwrap.