Object reflection c# - c#

I want to generate the right object with one code line and not a switch case because always when a new device is added I have to add a new line.
Is it possible to do that in one line without switch case?
public static Device GetDevice(Device.enumDevice TypeOfDevice, string alias)
{
// Create the Object with using reflection
switch (TypeOfDevice)
{
case Device.enumDevice.A34411:
return new A34411(string alias);
break;
case Device.enumDevice.N5744:
return new N5744(string alias);
break;
default:
throw new NotImplementedException();
}
return null;
}

You could store the factory methods as delegates in a dictionary
private static Dictionary<Device.enumDevice, Func<string, Device>> _factoryDict =
new Dictionary<Device.enumDevice, Func<string, Device>>{
[Device.enumDevice.A34411] = (alias) => new A34411(alias),
[Device.enumDevice.N5744] = (alias) => new N5744(alias),
};
...
public static Device GetDevice(Device.enumDevice TypeOfDevice, string alias)
{
if (_factoryDict.TryGetValue(TypeOfDevice, out var factory)) {
return factory(alias);
}
throw new NotImplementedException();
// No retun statement here, as it would be unreachable because of the throw statement.
}
Or, using reflection:
const string deviceNameSpace = "MyName.MyProject.Devices.";
public static Device GetDevice(Device.enumDevice deviceType, string alias)
{
string typeName = deviceNameSpace + deviceType.ToString();
Type type = Type.GetType(typeName, throwOnError: true);
return (Device)Activator.CreateInstance(type, alias);
}

An elegant approach would be to use Dependency Injection with "Named Type Registrations"

Fast, but not quite a complete example:
public abstract class Device
{
protected Device(string alias)
{
Alias = alias;
}
public string Alias { get; }
}
public class A1 : Device
{
public A1(string alias) : base(alias) { }
}
public class A2 : Device
{
public A2(string alias) : base(alias) { }
}
class DeviceAttribute : Attribute
{
public DeviceAttribute(Type type)
{
Type = type;
}
public Type Type { get; }
}
public enum DeviceEnum
{
[Device(typeof(A1))]
A1,
[Device(typeof(A2))]
A2
}
public static class DeviceEnumExtension
{
public static Device GetInstance(this DeviceEnum obj, string alias)
{
var member = typeof(DeviceEnum).GetMember(obj.ToString());
if (member[0].GetCustomAttributes(typeof(DeviceAttribute), false)[0] is DeviceAttribute deviceAttr)
{
var ctor = deviceAttr.Type.GetConstructor(new[] {typeof(string)});
return ctor.Invoke(new object[] {alias}) as Device;
}
return null;
}
}
public class UnitTest1
{
[Fact]
public void Test1()
{
// Arrange
var a1 = DeviceEnum.A1;
var a2 = DeviceEnum.A2;
// Act
var instanceA1 = a1.GetInstance("A1");
var instanceA2 = a2.GetInstance("A2");
// Assert
Assert.Equal(typeof(A1), instanceA1.GetType());
Assert.Equal(typeof(A2), instanceA2.GetType());
Assert.Equal("A1", instanceA1.Alias);
Assert.Equal("A2", instanceA2.Alias);
}
}

Related

How to use Generic interface with two type in return of method

I need to create an interface with 2 type and use it as a method return value.
public interface StringLong<T1,T2>
where T1 : string
where T2 : long
{}
StringLong<T1,T2> method StringLong<T1,T2>()
It makes no sense to define an interface with two generic types that you constrain to just string and long.
It sounds like you just want a tuple:
(string, long) MyMethod()
{
return ("Hello", 42L);
}
You can even name the return values:
(string message, long meaningOfLife) MyMethod()
{
return ("Hello", 42L);
}
Then you can write:
var result = MyMethod();
Console.WriteLine(result.message);
Console.WriteLine(result.meaningOfLife);
I think is the functionality you are trying to achieve (from the comments). Since the return might be of either string or long there common ancestor is object.
Once you have the value you can use pattern matching to cast the result into the appropriate type:
static class Program
{
static void Main(string[] args)
{
var obj = MethodReturnsStringOrLong(1722);
switch (obj)
{
case string str:
Console.WriteLine($"String is {str}");
break;
case long lng:
Console.WriteLine($"Long is {lng}");
break;
default:
throw new NotSupportedException();
}
}
public static object MethodReturnsStringOrLong(int input)
{
if (input % 2 == 0)
{
return 1928374028203384L;
}
else
{
return "ASIDJMFHSOASKSJHD";
}
}
}
An alternative is the create your own common ancestor, like the class Value below that might contains either a long and/or a string.
public class Value
{
public Value(long longValue)
{
LongValue = longValue;
}
public Value(string stringValue)
{
StringValue = stringValue;
}
public long? LongValue { get; }
public string StringValue { get; }
}
static class Program
{
static void Main(string[] args)
{
var obj = MethodReturnsStringOrLong(1722);
if (obj.LongValue.HasValue)
{
Console.WriteLine($"Long is {obj.LongValue.Value}");
}
if (!string.IsNullOrEmpty(obj.StringValue))
{
Console.WriteLine($"String is {obj.StringValue}");
}
}
public static Value MethodReturnsStringOrLong(int input)
{
if (input % 2 == 0)
{
return new Value(1928374028203384L);
}
else
{
return new Value("ASIDJMFHSOASKSJHD");
}
}
}

Pass generic type to Theory [duplicate]

In xUnit I can have a Theory test that uses generics in this form:
[Theory]
[MemberData(SomeScenario)]
public void TestMethod<T>(T myType)
{
Assert.Equal(typeof(double), typeof(T));
}
public static IEnumerable<object[]> SomeScenario()
{
yield return new object[] { 1.23D };
}
Which will give me the generic T parameter as double. Is it possible to use MemberData to specify the generic type parameter for a test with a signature like:
[Theory]
[MemberData(SomeTypeScenario)]
public void TestMethod<T>()
{
Assert.Equal(typeof(double), typeof(T));
}
If it is not possible with MemberData or any other provided attribute (which I'm suspecting that it isn't), is it possible to create an attribute for Xunit that can achieve this? Maybe something along the lines of specifying Types in the Scenarios method and using reflection in a similar manner to Jon Skeet's answer here: Generics in C#, using type of a variable as parameter
You can simply include Type as an input parameter instead. E.g.:
[Theory]
[MemberData(SomeTypeScenario)]
public void TestMethod(Type type) {
Assert.Equal(typeof(double), type);
}
public static IEnumerable<object[]> SomeScenario() {
yield return new object[] { typeof(double) };
}
There is no need to go with generics on xunit.
Edit (if you really need generics)
1) You need to subclass ITestMethod to persist generic method info, it also has to implement IXunitSerializable
// assuming namespace Contosco
public class GenericTestMethod : MarshalByRefObject, ITestMethod, IXunitSerializable
{
public IMethodInfo Method { get; set; }
public ITestClass TestClass { get; set; }
public ITypeInfo GenericArgument { get; set; }
/// <summary />
[Obsolete("Called by the de-serializer; should only be called by deriving classes for de-serialization purposes")]
public GenericTestMethod()
{
}
public GenericTestMethod(ITestClass #class, IMethodInfo method, ITypeInfo genericArgument)
{
this.Method = method;
this.TestClass = #class;
this.GenericArgument = genericArgument;
}
public void Serialize(IXunitSerializationInfo info)
{
info.AddValue("MethodName", (object) this.Method.Name, (Type) null);
info.AddValue("TestClass", (object) this.TestClass, (Type) null);
info.AddValue("GenericArgumentAssemblyName", GenericArgument.Assembly.Name);
info.AddValue("GenericArgumentTypeName", GenericArgument.Name);
}
public static Type GetType(string assemblyName, string typeName)
{
#if XUNIT_FRAMEWORK // This behavior is only for v2, and only done on the remote app domain side
if (assemblyName.EndsWith(ExecutionHelper.SubstitutionToken, StringComparison.OrdinalIgnoreCase))
assemblyName = assemblyName.Substring(0, assemblyName.Length - ExecutionHelper.SubstitutionToken.Length + 1) + ExecutionHelper.PlatformSuffix;
#endif
#if NET35 || NET452
// Support both long name ("assembly, version=x.x.x.x, etc.") and short name ("assembly")
var assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.FullName == assemblyName || a.GetName().Name == assemblyName);
if (assembly == null)
{
try
{
assembly = Assembly.Load(assemblyName);
}
catch { }
}
#else
System.Reflection.Assembly assembly = null;
try
{
// Make sure we only use the short form
var an = new AssemblyName(assemblyName);
assembly = System.Reflection.Assembly.Load(new AssemblyName { Name = an.Name, Version = an.Version });
}
catch { }
#endif
if (assembly == null)
return null;
return assembly.GetType(typeName);
}
public void Deserialize(IXunitSerializationInfo info)
{
this.TestClass = info.GetValue<ITestClass>("TestClass");
string assemblyName = info.GetValue<string>("GenericArgumentAssemblyName");
string typeName = info.GetValue<string>("GenericArgumentTypeName");
this.GenericArgument = Reflector.Wrap(GetType(assemblyName, typeName));
this.Method = this.TestClass.Class.GetMethod(info.GetValue<string>("MethodName"), true).MakeGenericMethod(GenericArgument);
}
}
2) You need to write your own discoverer for generic methods, it has to be subclass of IXunitTestCaseDiscoverer
// assuming namespace Contosco
public class GenericMethodDiscoverer : IXunitTestCaseDiscoverer
{
public GenericMethodDiscoverer(IMessageSink diagnosticMessageSink)
{
DiagnosticMessageSink = diagnosticMessageSink;
}
protected IMessageSink DiagnosticMessageSink { get; }
public IEnumerable<IXunitTestCase> Discover(ITestFrameworkDiscoveryOptions discoveryOptions,
ITestMethod testMethod, IAttributeInfo factAttribute)
{
var result = new List<IXunitTestCase>();
var types = factAttribute.GetNamedArgument<Type[]>("Types");
foreach (var type in types)
{
var typeInfo = new ReflectionTypeInfo(type);
var genericMethodInfo = testMethod.Method.MakeGenericMethod(typeInfo);
var genericTestMethod = new GenericTestMethod(testMethod.TestClass, genericMethodInfo, typeInfo);
result.Add(
new XunitTestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(),
genericTestMethod));
}
return result;
}
}
3) Finally you can make your attribute for generic methods and hook it to your custom discoverer by XunitTestCaseDiscoverer attribute
// assuming namespace Contosco
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
[XunitTestCaseDiscoverer("Contosco.GenericMethodDiscoverer", "Contosco")]
public sealed class GenericMethodAttribute : FactAttribute
{
public Type[] Types { get; private set; }
public GenericMethodAttribute(Type[] types)
{
Types = types;
}
}
Usage:
[GenericMethod(new Type[] { typeof(double), typeof(int) })]
public void TestGeneric<T>()
{
Assert.Equal(typeof(T), typeof(double));
}

Polymorphic object creation without IF condition

I have an abstract class like this:
public abstract class Records
{
public string Type;
public string Source;
public int Value;
protected Records(string type, string source, int value)
{
Type = type;
Source = source;
Value = value;
}
}
I would like to create many classes inheriting this class, and filling their Type field with a value coming from a static class like this:
public static class ContentTypesString
{
public static string DocumentNew { get { return "Document - New this Month"; }}
public static string HeadlinesNew { get { return "Headlines - New this Month"; }}
etc...
}
I would like to be able to create those child classes without having a test "if foo == "document" then type = ContentTypesString.DocumentNew" or an equivalent switch case (I really have a lot of cases)
Is there a design pattern that suits my needs?
EDIT : As several people pointed out, i should show how i create my instances.
private delegate SPListItemCollection Query(SPWeb web, DateTime startDate, DateTime endDate);
private readonly Query _queries;
#region Constructors
public QueryHandler(SPWeb web, DateTime startTimeSelectedDate, DateTime endTimeSelectedDate)
{
if (web == null) throw new ArgumentNullException("web");
_web = web;
_startTimeSelectedDate = startTimeSelectedDate;
_endTimeSelectedDate = endTimeSelectedDate;
RecordsList = new List<Records>();
// Query Invocation List
_queries = NumberPagePerMonthQuery.PreparedQuery;
_queries += NumberDocumentsPerMonthQuery.PreparedQuery;
_queries += NumberHeadlinesPerMonthQuery.PreparedQuery;
_queries += NumberLeaderboxPerMonthQuery.PreparedQuery;
_queries += NumberNewsPerMonthQuery.PreparedQuery;
_queries += NumberPagesModifiedPerMonthQuery.PreparedQuery;
_queries += NumberPicturesPerMonthQuery.PreparedQuery;
_queries += NumberTeasingPerMonthQuery.PreparedQuery;
}
#endregion Constructors
#region Public Methods
// what about NullReferenceException ? C#6 : item?.Foreach(item => {}); ?
/*** NO C#6 compiler in VS2012... ***/
public void Queries()
{
foreach (var del in _queries.GetInvocationList())
{
var queryresult =
(SPListItemCollection) del.DynamicInvoke(_web, _startTimeSelectedDate, _endTimeSelectedDate);
RecordsList.Add(new Records(del.Method.Name, _web.Title, queryresult.Count));
}
}
EDIT² :
The solution i chose
public List<IQuery> QueryList { get; } // no delegate anymore, and static classes became implementations of IQuery interface.
#region Constructors
public QueryHandler(SPWeb web, DateTime startTimeSelectedDate, DateTime endTimeSelectedDate)
{
if (web == null) throw new ArgumentNullException("web");
_web = web;
_startTimeSelectedDate = startTimeSelectedDate;
_endTimeSelectedDate = endTimeSelectedDate;
RecordsList = new List<Records>();
QueryList = new List<IQuery>
{
new NumberDocumentsPerMonthQuery(),
new NumberHeadlinesPerMonthQuery(),
new NumberLeaderboxPerMonthQuery(),
new NumberNewsPerMonthQuery(),
new NumberPagePerMonthQuery(),
new NumberPagesModifiedPerMonthQuery(),
new NumberPicturesPerMonthQuery(),
new NumberTeasingPerMonthQuery()
};
}
#endregion Constructors
#region Public Methods
// what about NullReferenceException ? C#6 : item?.Foreach(item => {}); ?
/*** NO C#6 compiler in VS2012... ***/
public void Queries()
{
foreach (var query in QueryList)
{
var queryresult = query.PreparedQuery(_web, _startTimeSelectedDate, _endTimeSelectedDate);
RecordsList.Add(query.CreateRecord(_web.Title, queryresult.Count));
}
}
Record class follow the implementation suggested by #dbraillon
Implementation of IQuery interface were added the method :
public Records CreateRecord(string source, int value)
{
return new ModifiedPagesPerMonthRecord(source, value); //or another child of Record class.
}
And voilĂ . Thank you all for the help.
You want to make collection of records, by string code of object type, and parameters.
One of many way to do it - use builder.
Firstly we need to configurate builder:
var builder = new RecordBuilder()
.RegisterBuilder("document", (source, value) => new Document(source, value))
.RegisterBuilder("headlines", (source, value) => new Headlines(source, value));
here we specify how to build record with code "document" and "headlines".
To build a record call:
builder.Build("document", "source", 1);
Builder code can by something like this
(here we look if we know how to build record of the passed type and make it):
public class RecordBuilder
{
public Records Build(string code, string source, int value)
{
Func<string, int, Records> buildAction;
if (recordBuilders.TryGetValue(code, out buildAction))
{
return buildAction(source, value);
}
return null;
}
public RecordBuilder RegisterBuilder(string code, Func<string, int, Records> buildAction)
{
recordBuilders.Add(code, buildAction);
return this;
}
private Dictionary<string, Func<string, int, Records>> recordBuilders = new Dictionary<string, Func<string, int, Records>> ();
}
public class Document : Records
{
public Document(string source, int value) : base(ContentTypesString.DocumentNew, source, value)
{
}
}
public class Headlines : Records
{
public Headlines(string source, int value) : base(ContentTypesString.HeadlinesNew, source, value)
{
}
}
Is that what you need ?
public abstract class Records
{
public string Type;
public string Source;
public int Value;
protected Records(string type, string source, int value)
{
Type = type;
Source = source;
Value = value;
}
}
public class DocumentRecords : Records
{
public DocumentRecords(string source, int value)
: base(ContentTypesString.DocumentNew, source, value) // use here
{
}
}
public class HeadlinesRecords : Records
{
public HeadlinesRecords(string source, int value)
: base(ContentTypesString.HeadlinesNew, source, value) // use here
{
}
}
public static class ContentTypesString
{
public static string DocumentNew { get { return "Document - New this Month"; } }
public static string HeadlinesNew { get { return "Headlines - New this Month"; } }
}

xUnit theory test using generics

In xUnit I can have a Theory test that uses generics in this form:
[Theory]
[MemberData(SomeScenario)]
public void TestMethod<T>(T myType)
{
Assert.Equal(typeof(double), typeof(T));
}
public static IEnumerable<object[]> SomeScenario()
{
yield return new object[] { 1.23D };
}
Which will give me the generic T parameter as double. Is it possible to use MemberData to specify the generic type parameter for a test with a signature like:
[Theory]
[MemberData(SomeTypeScenario)]
public void TestMethod<T>()
{
Assert.Equal(typeof(double), typeof(T));
}
If it is not possible with MemberData or any other provided attribute (which I'm suspecting that it isn't), is it possible to create an attribute for Xunit that can achieve this? Maybe something along the lines of specifying Types in the Scenarios method and using reflection in a similar manner to Jon Skeet's answer here: Generics in C#, using type of a variable as parameter
You can simply include Type as an input parameter instead. E.g.:
[Theory]
[MemberData(SomeTypeScenario)]
public void TestMethod(Type type) {
Assert.Equal(typeof(double), type);
}
public static IEnumerable<object[]> SomeScenario() {
yield return new object[] { typeof(double) };
}
There is no need to go with generics on xunit.
Edit (if you really need generics)
1) You need to subclass ITestMethod to persist generic method info, it also has to implement IXunitSerializable
// assuming namespace Contosco
public class GenericTestMethod : MarshalByRefObject, ITestMethod, IXunitSerializable
{
public IMethodInfo Method { get; set; }
public ITestClass TestClass { get; set; }
public ITypeInfo GenericArgument { get; set; }
/// <summary />
[Obsolete("Called by the de-serializer; should only be called by deriving classes for de-serialization purposes")]
public GenericTestMethod()
{
}
public GenericTestMethod(ITestClass #class, IMethodInfo method, ITypeInfo genericArgument)
{
this.Method = method;
this.TestClass = #class;
this.GenericArgument = genericArgument;
}
public void Serialize(IXunitSerializationInfo info)
{
info.AddValue("MethodName", (object) this.Method.Name, (Type) null);
info.AddValue("TestClass", (object) this.TestClass, (Type) null);
info.AddValue("GenericArgumentAssemblyName", GenericArgument.Assembly.Name);
info.AddValue("GenericArgumentTypeName", GenericArgument.Name);
}
public static Type GetType(string assemblyName, string typeName)
{
#if XUNIT_FRAMEWORK // This behavior is only for v2, and only done on the remote app domain side
if (assemblyName.EndsWith(ExecutionHelper.SubstitutionToken, StringComparison.OrdinalIgnoreCase))
assemblyName = assemblyName.Substring(0, assemblyName.Length - ExecutionHelper.SubstitutionToken.Length + 1) + ExecutionHelper.PlatformSuffix;
#endif
#if NET35 || NET452
// Support both long name ("assembly, version=x.x.x.x, etc.") and short name ("assembly")
var assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.FullName == assemblyName || a.GetName().Name == assemblyName);
if (assembly == null)
{
try
{
assembly = Assembly.Load(assemblyName);
}
catch { }
}
#else
System.Reflection.Assembly assembly = null;
try
{
// Make sure we only use the short form
var an = new AssemblyName(assemblyName);
assembly = System.Reflection.Assembly.Load(new AssemblyName { Name = an.Name, Version = an.Version });
}
catch { }
#endif
if (assembly == null)
return null;
return assembly.GetType(typeName);
}
public void Deserialize(IXunitSerializationInfo info)
{
this.TestClass = info.GetValue<ITestClass>("TestClass");
string assemblyName = info.GetValue<string>("GenericArgumentAssemblyName");
string typeName = info.GetValue<string>("GenericArgumentTypeName");
this.GenericArgument = Reflector.Wrap(GetType(assemblyName, typeName));
this.Method = this.TestClass.Class.GetMethod(info.GetValue<string>("MethodName"), true).MakeGenericMethod(GenericArgument);
}
}
2) You need to write your own discoverer for generic methods, it has to be subclass of IXunitTestCaseDiscoverer
// assuming namespace Contosco
public class GenericMethodDiscoverer : IXunitTestCaseDiscoverer
{
public GenericMethodDiscoverer(IMessageSink diagnosticMessageSink)
{
DiagnosticMessageSink = diagnosticMessageSink;
}
protected IMessageSink DiagnosticMessageSink { get; }
public IEnumerable<IXunitTestCase> Discover(ITestFrameworkDiscoveryOptions discoveryOptions,
ITestMethod testMethod, IAttributeInfo factAttribute)
{
var result = new List<IXunitTestCase>();
var types = factAttribute.GetNamedArgument<Type[]>("Types");
foreach (var type in types)
{
var typeInfo = new ReflectionTypeInfo(type);
var genericMethodInfo = testMethod.Method.MakeGenericMethod(typeInfo);
var genericTestMethod = new GenericTestMethod(testMethod.TestClass, genericMethodInfo, typeInfo);
result.Add(
new XunitTestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(),
genericTestMethod));
}
return result;
}
}
3) Finally you can make your attribute for generic methods and hook it to your custom discoverer by XunitTestCaseDiscoverer attribute
// assuming namespace Contosco
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
[XunitTestCaseDiscoverer("Contosco.GenericMethodDiscoverer", "Contosco")]
public sealed class GenericMethodAttribute : FactAttribute
{
public Type[] Types { get; private set; }
public GenericMethodAttribute(Type[] types)
{
Types = types;
}
}
Usage:
[GenericMethod(new Type[] { typeof(double), typeof(int) })]
public void TestGeneric<T>()
{
Assert.Equal(typeof(T), typeof(double));
}

How to have a method return a specific type?

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);
}
}
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
{
}
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;
}
}

Categories

Resources