Reputation: 24695
I have a method which returns the base type, I want an overload (preferably, but a new method would be fine) that returns a parent class instead, so that I could do something like:
DynamicClass cl = new DynamicClass(...);
var dict = cl.CreateObject<DynamicDictionary>("ClassName");
dict.CallAddOnMethod("test");
Here is the code I have tried, but I can't seem to get to DynamicDictionary
public sealed class DynamicClass : DynamicBaseClass
{
public DynamicObject CreateObject(params object[] args)
{
Debug.Assert(args.Length > 0);
object handle = InvokeMethod(CreateObjectMethod, args);
return new DynamicObject(bcAssembly, (string)args[0], handle);
}
public T CreateObject<T>(params object[] args)
{
Debug.Assert(args.Length > 0);
object handle = InvokeMethod(CreateObjectMethod, args);
DynamicObject item = new DynamicObject(bcAssembly, (string)args[0], handle)
return (T)item; // cant do this?
}
}
public class DynamicObject : DynamicBaseClass
{
private const string CallMethod = "Call";
public DynamicObject(Assembly assembly, string parentName, object classHandle)
: base(assembly, parentName, classHandle)
{
}
public object Call(string methodName, params object[] paramList)
{
return InvokeMethod(CallMethod, paramList);
}
}
public sealed class DynamicObject<T> : DynamicObject
{
private const string CallMethod = "Call";
public DynamicObject(Assembly assembly, string parentName, object classHandle)
: base(assembly, parentName, classHandle)
{
}
}
public sealed class DynamicDictionary : DynamicObject
{
private const string AddOnMethod = "AddOn";
public DynamicDictionary(Assembly assembly, string parentName, object classHandle)
: base(assembly, parentName, classHandle)
{
}
public int CallAddOnMethod(string name)
{
return (int)Call(AddOnMethod, name);
}
}
Upvotes: 1
Views: 193
Reputation: 38704
One alternative is to load codes, compile the codes and execute the compiled results dynamically. The following example uses a private string as a template code source (you may load it from a text file):
using Microsoft.CSharp;
public class MyTemplate : IDisposable {
private const string _SourceCodeTemplate = @"
using System;
public class {0} {{ // {{0}} Class name
public {0} CreateInstance()
{{
{0} instance;
//... some codes here to create instance
return instance;
}}
public {1} {2}() {{ // {{1}} method result, {{2}} method name
{1} result;
// some codes here for the result
return result;
}}
}}";
public T CallInstanceMethod<T>(string className, string callMethod,
string callMethodResult,
params object[] paramList) {
string codes;
// build codes dynamically
codes = string.Format(_SourceCodeTemplate, className,
callMethodResult, callMethod);
CSharpCodeProvider codeProvider = new CSharpCodeProvider();
CompilerParameters parameters = new CompilerParameters();
parameters.GenerateExecutable = false;
parameters.GenerateInMemory = true;
parameters.IncludeDebugInformation = false;
foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies())
{
parameters.ReferencedAssemblies.Add(asm.Location);
}
// compile the codes
CompilerResults cr= codeProvider.CompileAssemblyFromSource(parameters, codes);
var csInstance = cr.CompiledAssembly.CreateInstance(className);
Type type = csInstance.GetType();
var methodForInstance = type.GetMethod(callMethod);
object value;
value = _methodForInstance.Invoke(csInstance, paramList);
return (T)value;
}
}
Upvotes: 0
Reputation: 27367
In your template, you should require that the type is a subclass of your dynamic object:
I.e.
var blah_b = test<b>();
blah_b.Dump();
var blah_c = test<c>();
blah_c.Dump();
-
public T test<T>() where T : a
{
var item = Activator.CreateInstance(typeof(T));
return (T)(item);
}
public class a
{
}
public class b : a
{
}
public class c : a
{
}
Upvotes: 1