ciao,
qualcuno sa come posso richiamare un assembly creato dinamicamente in memoria per passarlo come ReferencedAssemblies di CompilerParameters (senza scriverlo su file)?
mi spiego meglio :
codice:
public static class Estensore<T>
{
public static T Estendi(object tipo, string nomeClasse, string nameSpace, Dictionary<string,string> proprieta)
{
CSharpCodeProvider CSharpCodeProvider = new CSharpCodeProvider();
ICodeCompiler Compilatore = CSharpCodeProvider.CreateCompiler();
CompilerParameters ParametriCompilatore = new CompilerParameters();
ParametriCompilatore.GenerateInMemory = true;
ParametriCompilatore.IncludeDebugInformation = true;
foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies())
{
try
{
ParametriCompilatore.ReferencedAssemblies.Add(asm.Location);
}
catch
{
return default(T);
}
}
StringBuilder CodiceSorgente = new StringBuilder();
CodiceSorgente.Append("using System;");
CodiceSorgente.Append("\n");
CodiceSorgente.Append("using System.Collections.Generic;");
CodiceSorgente.Append("\n");
CodiceSorgente.Append("using Test;");
CodiceSorgente.Append("\n");
CodiceSorgente.Append("using System.Text;");
CodiceSorgente.Append("\n");
CodiceSorgente.Append("using Microsoft.CSharp;");
CodiceSorgente.Append("\n");
CodiceSorgente.Append("using System.CodeDom.Compiler;");
CodiceSorgente.Append("\n");
CodiceSorgente.Append("namespace "); CodiceSorgente.Append(nameSpace);
CodiceSorgente.Append("\n");
CodiceSorgente.Append("{\n");
CodiceSorgente.Append("public class "); CodiceSorgente.Append(nomeClasse);
CodiceSorgente.Append(" : "); CodiceSorgente.Append(tipo.GetType().ToString());
CodiceSorgente.Append("\n");
CodiceSorgente.Append("{\n");
foreach(string nomeProprieta in proprieta.Keys)
{
string nomeProprietaMaiuscola = nomeProprieta.Substring(0,1).ToUpper() + nomeProprieta.Substring(1,nomeProprieta.Length-1);
string minuscola = nomeProprieta.Substring(0,1).ToLower() + nomeProprieta.Substring(1,nomeProprieta.Length-1);
CodiceSorgente.Append("public string "); CodiceSorgente.Append(nomeProprietaMaiuscola);
CodiceSorgente.Append("{ get{ return " + minuscola + ";} set{ " + minuscola + " = value; }}"); CodiceSorgente.Append("\n");
CodiceSorgente.Append("\n");
CodiceSorgente.Append("string ");
CodiceSorgente.Append(minuscola); CodiceSorgente.Append(" = ");
CodiceSorgente.Append(@"""");CodiceSorgente.Append(proprieta[nomeProprieta]);CodiceSorgente.Append(@"""");
CodiceSorgente.Append(";");
}
CodiceSorgente.Append("public "); CodiceSorgente.Append(nomeClasse); CodiceSorgente.Append("() {");
CodiceSorgente.Append("\n}\n}\n}");
CompilerResults RisultatoCompilatore = Compilatore.CompileAssemblyFromSource(ParametriCompilatore, CodiceSorgente.ToString());
if (RisultatoCompilatore.Errors.HasErrors)
{
foreach (CompilerError Errore in RisultatoCompilatore.Errors)
{
if (!Errore.IsWarning)
{
return default(T);
}
}
}
Type t = null;
for(int i = 0; i<RisultatoCompilatore.CompiledAssembly.GetTypes().Length;i++)
{
if(RisultatoCompilatore.CompiledAssembly.GetTypes()[i].Name==nomeClasse)
{
t = RisultatoCompilatore.CompiledAssembly.GetTypes()[i];
break;
}
}
object o = t.InvokeMember(nomeClasse, System.Reflection.BindingFlags.CreateInstance, null, null, null);
PropertyInfo[] properties = tipo.GetType().GetProperties//();
(
BindingFlags.CreateInstance
//| BindingFlags.GetField
| BindingFlags.GetProperty
| BindingFlags.Instance
//| BindingFlags.InvokeMethod
//| BindingFlags.NonPublic
| BindingFlags.Public
//| BindingFlags.OptionalParamBinding
);
foreach (PropertyInfo property in properties)
{
if (property.CanWrite)
{
object value = property.GetValue(tipo, null);
property.SetValue(o, value, null);
}
}
return (T)o;
}
}
usandolo così tutto funziona :
codice:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
namespace Test
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
User user = new User();
user.Password = "2312";
user.UserName ="paperino";
Dictionary<string, string> dizionario = new Dictionary<string, string>();
dizionario.Add("CodiceDiSicurezza", "123456");
user = Estensore<User>.Estendi(user, "SuperUser", "Test", dizionario);
writeProperty(user);
}
void writeProperty(User user)
{
PropertyInfo[] properties = user.GetType().GetProperties//();
(
BindingFlags.CreateInstance
//| BindingFlags.GetField
| BindingFlags.GetProperty
| BindingFlags.Instance
//| BindingFlags.InvokeMethod
//| BindingFlags.NonPublic
| BindingFlags.Public
//| BindingFlags.OptionalParamBinding
);
this.dataGridView1.DataSource = properties;
}
}
public class User
{
public string UserName { get; set; }
public string Password { get; set; }
}
}
ottengo ovviamente le proprietà della classe "SuperUser" più quelle ereditate da User.
Il punto e che mi piacerebbe fare una cosa del genere :
codice:
User user = new User();
user.Password = "2312";
user.UserName ="paperino";
Dictionary<string, string> dizionario = new Dictionary<string, string>();
dizionario.Add("CodiceDiSicurezza", "123456");
user = Estensore<User>.Estendi(user, "SuperUser", "Test", dizionario);
//writeProperty(user);
dizionario.Clear();
dizionario.Add("CodiceDiSicurezza2", "123456");
user = Estensore<User>.Estendi(user, "Admin", "Test", dizionario);
writeProperty(user);
in questo caso, la seconda volta che chiamo Estendi, eredito da "SuperUser" (non da User), in quanto il suo nuovo tipo è appunto "SuperUser".
ora il problema è che non voglio scrivere l'assembly su file, lo voglio tenere in memoria, quindi volevo sapere se esiste un modo per caricarlo nei parametri del compilatore senza passare location.
codice:
foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies())
{
try
{
ParametriCompilatore.ReferencedAssemblies.Add(asm.????);
}
catch
{
return default(T);
}
}
sicuramente è una ca***ta, ma ora ho un vuoto.
Grazie in anticipo per l'attenzione.