11 public class MockInterfaceOnObject<IInterface>
12 where IInterface:class
Am vrut sa integrez backgroundworker-ul cu incarcarea din o tabela a obiectelor – pentru a afisa intr-un grid incarcarea (nu astept pina se incarca toate …)
Prima oara am zis : ok, pare sa fie destul de usor – incarc obiectele in DoWork-ul lui si trimit evenimente la adaugarea fiecarui copil(rind) care sa le prind si … gata
Wrong…. trebuia sa imi dau seama ca evenimentele provin din alt thread decit al formei – si in consecinta trebuie sa fac begininvoke
Ok, mi-am zis – atunci de ce sa nu invoc direct ReportProgress ca sa raportez progresul operatiei si sa ma folosesc direct de evenimentele backgroundworker-ului?
Bun-dar obiectele mele sunt intr-o clasa separata- care nu stie NIMIC despre windowsforms – si e bine sa fie asa…
Care sa fie solutia?
Logic- o interfata care sa contina metodele principale din control, de genul:
22 public interface IReportProgress
23 {
24 void ReportProgress(int percentProgress, object State);
25 void CancelAsync();
26 }
Am zis-super, tot ce am de facut este sa fac cast de la control la interfata, sa o pasez la obiectul de incarcare si gata!
Wrong… cast de la control la interfata – acolo a fost problema adevarata…
Desi control-ul are TOATE metodele interfetei, deci TEORETIC implementeaza interfata, totusi nu se poate face cast … NASOL!
Asa ca am deschis un forum pe RONUA si , in acelasi timp, m-am apucat sa fac o clasa generica care sa rezolve problema cast-ului intre un obiect si o interfata care contine metodele obiectului.
Am ajuns la o clasa
11 public class MockInterfaceOnObject<IInterface>
12 where IInterface:class
cu 2 metode principale:
18 public static T MockObject<T>()
19 where T:class
care intoarce un obiect NOU care il mosteneste pe T(backgroundworker) si implementeaza interfata IInterface – se foloseste cind vreti sa creati un obiect nou
25 public static IInterface MockInterface(object obj)
care construieste un obiect nou ce are un constructor ce primeste ca argument obiectul trimis si implementeaza interfata facind apel la functiile corespunzatoare obiectului trimis – se foloseste cind obiectul deja exista , are anumite proprietati setate si vreti sa il folositi.
Nu am putut folosi metoda 1 pentru a face new pe backgroundworker -nu ca nu ar fi compilat, dimpotriva… Dar design-time de la WindowsForms se incapatina sa dea eroare.
Asa ca am folosit 2, cu ceva de genul
70 MockInterfaceOnObject<IReportProgress>.MockInterface(backgroundWorker1)
Si a mers OK
Pe RONUA somalezu a dat inca o solutie, cu Real Proxy care pare sa fie interesanta. O sa o studiez. Pina atunci , iata codul:
using System;
using System.Collections.Generic;
using System.Text;
using System.CodeDom.Compiler;
using System.Reflection;
using Microsoft.CSharp;
using System.IO;
namespace MockInterface
{
public class MockInterfaceOnObject<IInterface>
where IInterface:class
{
private static Type TypeInterface()
{
return typeof(IInterface);
}
public static T MockObject<T>()
where T:class
{
return ObjectWithInterface(typeof(T), GenerateInheritance(typeof(T)), null) as T;
}
public static T MockObject<T>(T obj)
where T : class
{
return ObjectWithInterface(typeof(T), GenerateEncapsulation(typeof(T)), obj) as T;
}
public static IInterface MockInterface(Type t)
{
return ObjectWithInterface(t, GenerateInheritance(t), null) as IInterface;
}
public static IInterface MockInterface(object obj)
{
return ObjectWithInterface(obj.GetType(), GenerateEncapsulation(obj.GetType()), obj) as IInterface;
}
private static string CodeBase(string pathfile)
{
if (pathfile == null)
return null;
if (pathfile.IndexOf(“file:///”) == 0)
pathfile = pathfile.Substring(“file:///”.Length);
return pathfile;
}
private static string CodeBase(Assembly a)
{
return CodeBase(a.CodeBase);
}
public static object ObjectWithInterface(object Existing)
{
return null;
}
public static object ObjectWithInterface(Type t,string Code,params object[] args)
{
CSharpCodeProvider cs = new CSharpCodeProvider();
CompilerParameters cp = new CompilerParameters();
cp.GenerateExecutable = false;
cp.GenerateInMemory = true;
cp.ReferencedAssemblies.AddRange(new string[] { CodeBase(t.Assembly), CodeBase(TypeInterface().Assembly) });
foreach (AssemblyName a in t.Assembly.GetReferencedAssemblies())
{
string pathfile = CodeBase(a.CodeBase);
if (pathfile != null && (!cp.ReferencedAssemblies.Contains(pathfile)))
cp.ReferencedAssemblies.Add(pathfile);
}
CompilerResults cr = cs.CompileAssemblyFromSource(cp, new string[1] { Code });
if (cr.Errors.Count > 0)
{
CompilerError ce = cr.Errors[0];
throw (new ArgumentException(“Can not compile file : “ + ce.ErrorText + ” Line:” + ce.Line));
}
return Activator.CreateInstance(cr.CompiledAssembly.GetExportedTypes()[0],args);
}
private static string GenerateInheritance(Type t)
{
StringBuilder sb=new StringBuilder();
sb.AppendLine(“namespace “ + t.Namespace);
sb.AppendLine(“{“);
sb.AppendLine(“public class My” + t.Name + ” : “ + t.Name + “,” + TypeInterface().FullName);
sb.AppendLine(“{“);
sb.AppendLine(“}”);
sb.AppendLine(“}”);
return sb.ToString();
}
private static string GenerateEncapsulation(Type t)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine(“namespace “ + t.Namespace);
sb.AppendLine(“{“);
sb.AppendLine(“public class My” + t.Name + ” : “ + TypeInterface().FullName);
sb.AppendLine(“{“);
sb.AppendLine(“private “ + t.Name + ” m_obj;”);
sb.AppendLine(“public My” + t.Name + “(“ + t.Name + ” obj){“);
sb.AppendLine(“m_obj = obj;”);
sb.AppendLine(“}”);
foreach (MethodInfo mi in TypeInterface().GetMethods())
{
bool isvoid = (mi.ReturnType== typeof(void));
string returntype = mi.ReturnParameter.ParameterType.FullName;
if (isvoid)
returntype = “void”;
sb.AppendLine(“public “ + returntype + ” “ + mi.Name + “(“);
sb.AppendLine(” “);
string strParams = ” “;
foreach(ParameterInfo pi in mi.GetParameters())
{
sb.Append(pi.ParameterType.FullName + ” “ + pi.Name + “,”);
strParams += pi.Name +“,”;
}
strParams = strParams.Substring(0, strParams.Length – 1);//remove ,
sb.Length =sb.Length-1;//remove ,
sb.AppendLine(“)”);
sb.AppendLine(“{“);
if (!isvoid)
sb.AppendLine(“return “);
sb.AppendLine(” m_obj.” + mi.Name + “(“ + strParams + “);”);
sb.AppendLine(“}”);
}
sb.AppendLine(“}”);
sb.AppendLine(“}”);
return sb.ToString();
}
}
}
( si nu stiu cind o sa ma obisnuiesc sa il si comentez…)