A) Сборка C# EXE и DLL на лету относительно проста.
B) Выполнение EXE означает, что запущено новое приложение. Загрузка DLL означает, что методы и функции могут использоваться в случаях, которые могут быть разделены между приложениями или проектами.
Теперь, самый быстрый и простой способ для компиляции EXE (или с умеренными изменениями, DLL) можно найти из MSDN или для вашего удобства:
Как скомпилировать C# DLL на лету, загрузить и использовать
private bool CompileCSharpCode(string script)
{
lvErrors.Items.Clear();
try
{
CSharpCodeProvider provider = new CSharpCodeProvider();
// Build the parameters for source compilation.
CompilerParameters cp = new CompilerParameters
{
GenerateInMemory = false,
GenerateExecutable = false, // True = EXE, False = DLL
IncludeDebugInformation = true,
OutputAssembly = "eventHandler.dll", // Compilation name
};
// Add in our included libs.
cp.ReferencedAssemblies.Add("System.dll");
cp.ReferencedAssemblies.Add("System.Windows.Forms.dll");
cp.ReferencedAssemblies.Add("Microsoft.VisualBasic.dll");
// Invoke compilation. This works from a string, but you can also load from a file using FromFile()
CompilerResults cr = provider.CompileAssemblyFromSource(cp, script);
if (cr.Errors.Count > 0)
{
// Display compilation errors.
foreach (CompilerError ce in cr.Errors)
{
//I have a listview to display errors.
lvErrors.Items.Add(ce.ToString());
}
return false;
}
else
{
lvErrors.Items.Add("Compiled Successfully.");
}
provider.Dispose();
}
catch (Exception e)
{
// never really reached, but better safe than sorry?
lvErrors.Items.Add("SEVERE! "+e.Message + e.StackTrace.ToString());
return false;
}
return true;
}
Теперь вы можете скомпилировать на лета , существует несколько различий между загрузкой библиотеки DLL. Как правило, вы добавляете его в качестве ссылки в Visual Studios для компиляции в проект. Это довольно легко, и вы, вероятно, сделали это много раз, но мы хотим использовать его в нашем текущем проекте, и мы не можем очень требовать от пользователя перекомпилировать весь проект каждый раз, когда они хотят протестировать свою новую DLL , Поэтому я просто буду обсуждать, как загрузить библиотеку «на лету». Другой термин здесь был бы «программным». Чтобы сделать это, после успешной компиляции, мы загружаем сборочного следующим образом:
Assembly assembly = Assembly.LoadFrom("yourfilenamehere.dll");
Если у вас есть AppDomain, вы можете попробовать это:
Assembly assembly = domain.Load(AssemblyName.GetAssemblyName("yourfilenamehere.dll"));
Теперь, Lib «ссылается», мы можем его открыть и использовать. Есть два способа сделать это. Один требует, чтобы вы знали, есть ли у метода параметры, другой проверит вас. Я сделаю это позже, вы можете проверить MSDN на другой.
// replace with your namespace.class
Type type = assembly.GetType("company.project");
if (type != null)
{
// replace with your function's name
MethodInfo method = type.GetMethod("method");
if (method != null)
{
object result = null;
ParameterInfo[] parameters = method.GetParameters();
object classInstance = Activator.CreateInstance(type, null);
if (parameters.Length == 0) // takes no parameters
{
// method A:
result = method.Invoke(classInstance, null);
// method B:
//result = type.InvokeMember("method", BindingFlags.InvokeMethod, null, classInstance, null);
}
else // takes 1+ parameters
{
object[] parametersArray = new object[] { }; // add parameters here
// method A:
result = method.Invoke(classInstance, parametersArray);
// method B:
//result = type.InvokeMember("method", BindingFlags.InvokeMethod, null, classInstance, parametersArray);
}
}
}
ПРОБЛЕМА: Первая компиляция отлично работает. Первое исполнение работает отлично. Тем не менее, попытка перекомпиляции будет ошибкой, заявив, что ваша * .PDP (база отладчика) используется. Я слышал некоторые намеки на маршалинг и AppDomains, но я не совсем понял проблему. Повторная компиляция завершится с ошибкой только после загрузки DLL.
Текущая попытка Маршалинг & & AppDomain:
class ProxyDomain : MarshalByRefObject
{
private object _instance;
public object Instance
{
get { return _instance; }
}
private AppDomain _domain;
public AppDomain Domain
{
get
{
return _domain;
}
}
public void CreateDomain(string friendlyName, System.Security.Policy.Evidence securityinfo)
{
_domain = AppDomain.CreateDomain(friendlyName, securityinfo);
}
public void UnloadDomain()
{
try
{
AppDomain.Unload(_domain);
}
catch (ArgumentNullException dne)
{
// ignore null exceptions
return;
}
}
private Assembly _assembly;
public Assembly Assembly
{
get
{
return _assembly;
}
}
private byte[] loadFile(string filename)
{
FileStream fs = new FileStream(filename, FileMode.Open);
byte[] buffer = new byte[(int)fs.Length];
fs.Read(buffer, 0, buffer.Length);
fs.Close();
return buffer;
}
public void LoadAssembly(string path, string typeName)
{
try
{
if (_domain == null)
throw new ArgumentNullException("_domain does not exist.");
byte[] Assembly_data = loadFile(path);
byte[] Symbol_data = loadFile(path.Replace(".dll", ".pdb"));
_assembly = _domain.Load(Assembly_data, Symbol_data);
//_assembly = _domain.Load(AssemblyName.GetAssemblyName(path));
_type = _assembly.GetType(typeName);
}
catch (Exception ex)
{
throw new InvalidOperationException(ex.ToString());
}
}
private Type _type;
public Type Type
{
get
{
return _type;
}
}
public void CreateInstanceAndUnwrap(string typeName)
{
_instance = _domain.CreateInstanceAndUnwrap(_assembly.FullName, typeName);
}
}
Ошибки _instance = _domain.CreateInstanceAndUnwrap (_assembly.FullName, TYPENAME); говоря, что моя Ассамблея не сериализуема. Попробовал добавить [Serializable] тег в мой класс без везения. Все еще исследует исправления.
Кажется, что вещи могут немного запутываться, когда вы не можете видеть, как они используются, так что это облегчает?
private void pictureBox1_Click(object sender, EventArgs e)
{
pd.UnloadDomain();
if (CompileCSharpCode(header + tScript.Text + footer))
{
try
{
pd.CreateDomain("DLLDomain", null);
pd.LoadAssembly("eventHandler.dll", "Events.eventHandler");
pd.CreateInstanceAndUnwrap("Events.eventHandler"); // Assembly not Serializable error!
/*if (pd.type != null)
{
MethodInfo onConnect = pd.type.GetMethod("onConnect");
if (onConnect != null)
{
object result = null;
ParameterInfo[] parameters = onConnect.GetParameters();
object classInstance = Activator.CreateInstance(pd.type, null);
if (parameters.Length == 0)
{
result = pd.type.InvokeMember("onConnect", BindingFlags.InvokeMethod, null, classInstance, null);
//result = onConnect.Invoke(classInstance, null);
}
else
{
object[] parametersArray = new object[] { };
//result = onConnect.Invoke(classInstance, parametersArray);
//result = type.InvokeMember("onConnect", BindingFlags.InvokeMethod, null, classInstance, parametersArray);
}
}
}*/
//assembly = Assembly.LoadFrom(null);
}
catch (Exception er)
{
MessageBox.Show("There was an error executing the script.\n>" + er.Message + "\n - " + er.StackTrace.ToString());
}
finally
{
}
}
}
Ваш процесс уже загрузил DLL, и вы не можете перезаписать это. – leppie
Вы хотите создать новый домен приложения и загрузить в него DLL. Затем, если вы хотите перекомпилировать, вы разорвите этот домен приложения. Таким образом, ваша основная программа работает в одном домене приложения, и она создает и управляет другим доменом приложения, который используется для загрузки сборки, над которой вы работаете. –
Вам нужны файлы PDB? Отлаживаются ли люди с помощью VS? Set IncludeDebugInformation = false, если они этого не делают. – MrMoDoJoJr