Purpose of Activator.CreateInstance with example? - c#

Can someone explain Activator.CreateInstance() purpose in detail?

Say you have a class called MyFancyObject like this one below:
class MyFancyObject
{
public int A { get;set;}
}
It lets you turn:
String ClassName = "MyFancyObject";
Into
MyFancyObject obj;
Using
obj = (MyFancyObject)Activator.CreateInstance("MyAssembly", ClassName))
and can then do stuff like:
obj.A = 100;
That's its purpose. It also has many other overloads such as providing a Type instead of the class name in a string. Why you would have a problem like that is a different story. Here's some people who needed it:
Createinstance() - Am I doing this right?
C# Using Activator.CreateInstance
Creating an object without knowing the class name at design time

Well i can give you an example why to use something like that. Think of a game where you want to store your level and enemies in an XML file. When you parse this file, you might have an element like this.
<Enemy X="10" Y="100" Type="MyGame.OrcGuard"/>
what you can do now is, create dynamically the objects found in your level file.
foreach(XmlNode node in doc)
var enemy = Activator.CreateInstance(null, node.Attributes["Type"]);
This is very useful, for building dynamic enviroments. Of course its also possible to use this for Plugin or addin scenarios and alot more.

My good friend MSDN can explain it to you, with an example
Here is the code in case the link or content changes in the future:
using System;
class DynamicInstanceList
{
private static string instanceSpec = "System.EventArgs;System.Random;" +
"System.Exception;System.Object;System.Version";
public static void Main()
{
string[] instances = instanceSpec.Split(';');
Array instlist = Array.CreateInstance(typeof(object), instances.Length);
object item;
for (int i = 0; i < instances.Length; i++)
{
// create the object from the specification string
Console.WriteLine("Creating instance of: {0}", instances[i]);
item = Activator.CreateInstance(Type.GetType(instances[i]));
instlist.SetValue(item, i);
}
Console.WriteLine("\nObjects and their default values:\n");
foreach (object o in instlist)
{
Console.WriteLine("Type: {0}\nValue: {1}\nHashCode: {2}\n",
o.GetType().FullName, o.ToString(), o.GetHashCode());
}
}
}
// This program will display output similar to the following:
//
// Creating instance of: System.EventArgs
// Creating instance of: System.Random
// Creating instance of: System.Exception
// Creating instance of: System.Object
// Creating instance of: System.Version
//
// Objects and their default values:
//
// Type: System.EventArgs
// Value: System.EventArgs
// HashCode: 46104728
//
// Type: System.Random
// Value: System.Random
// HashCode: 12289376
//
// Type: System.Exception
// Value: System.Exception: Exception of type 'System.Exception' was thrown.
// HashCode: 55530882
//
// Type: System.Object
// Value: System.Object
// HashCode: 30015890
//
// Type: System.Version
// Value: 0.0
// HashCode: 1048575

You can also do this -
var handle = Activator.CreateInstance("AssemblyName",
"Full name of the class including the namespace and class name");
var obj = handle.Unwrap();

A good example could be next: for instance you have a set of Loggers and you allows user to specify type to be used in runtime via configuration file.
Then:
string rawLoggerType = configurationService.GetLoggerType();
Type loggerType = Type.GetType(rawLoggerType);
ILogger logger = Activator.CreateInstance(loggerType.GetType()) as ILogger;
OR another case is when you have a common entities factory, which creates entity, and is also responsible on initialization of an entity by data received from DB:
(pseudocode)
public TEntity CreateEntityFromDataRow<TEntity>(DataRow row)
where TEntity : IDbEntity, class
{
MethodInfo methodInfo = typeof(T).GetMethod("BuildFromDataRow");
TEntity instance = Activator.CreateInstance(typeof(TEntity)) as TEntity;
return methodInfo.Invoke(instance, new object[] { row } ) as TEntity;
}

The Activator.CreateInstance method creates an instance of a specified type using the constructor that best matches the specified parameters.
For example, let's say that you have the type name as a string, and you want to use the string to create an instance of that type. You could use Activator.CreateInstance for this:
string objTypeName = "Foo";
Foo foo = (Foo)Activator.CreateInstance(Type.GetType(objTypeName));
Here's an MSDN article that explains it's application in more detail:
http://msdn.microsoft.com/en-us/library/wccyzw83.aspx

Building off of deepee1 and this, here's how to accept a class name in a string, and then use it to read and write to a database with LINQ. I use "dynamic" instead of deepee1's casting because it allows me to assign properties, which allows us to dynamically select and operate on any table we want.
Type tableType = Assembly.GetExecutingAssembly().GetType("NameSpace.TableName");
ITable itable = dbcontext.GetTable(tableType);
//prints contents of the table
foreach (object y in itable) {
string value = (string)y.GetType().GetProperty("ColumnName").GetValue(y, null);
Console.WriteLine(value);
}
//inserting into a table
dynamic tableClass = Activator.CreateInstance(tableType);
//Alternative to using tableType, using Tony's tips
dynamic tableClass = Activator.CreateInstance(null, "NameSpace.TableName").Unwrap();
tableClass.Word = userParameter;
itable.InsertOnSubmit(tableClass);
dbcontext.SubmitChanges();
//sql equivalent
dbcontext.ExecuteCommand("INSERT INTO [TableNme]([ColumnName]) VALUES ({0})", userParameter);

Coupled with reflection, I found Activator.CreateInstance to be very helpful in mapping stored procedure result to a custom class as described in the following answer.

Why would you use it if you already knew the class and were going to cast it?
Why not just do it the old fashioned way and make the class like you always make it? There's no advantage to this over the way it's done normally.
Is there a way to take the text and operate on it thusly:
label1.txt = "Pizza"
Magic(label1.txt) p = new Magic(lablel1.txt)(arg1, arg2, arg3);
p.method1();
p.method2();
If I already know its a Pizza there's no advantage to:
p = (Pizza)somefancyjunk("Pizza"); over
Pizza p = new Pizza();
but I see a huge advantage to the Magic method if it exists.

We used it for something like e.g.
public interface IExample
{
void DoSomethingAmazing();
}
public class ExampleA : IExample
{
public void DoSomethingAmazing()
{
Console.WriteLine("AAAA");
}
public void DoA()
{
Console.WriteLine("A")
}
}
public class ExampleB : IExample
{
public void DoSomethingAmazing()
{
Console.WriteLine("BBBB");
}
public void DoB()
{
Console.WriteLine("B")
}
}
and then provided the type serialized from a settings file
=> Even after compilation we can still change the applications behaviour by using different settings
Something like e.g.
public static class Programm
{
public static void Main()
{
var type = MagicMethodThatReadsASerializedTypeFromTheSettings();
var example = (IExample) Activator.CreateInstance(type);
example.DoSomethingAmazing();
switch(example)
{
case ExampleA a:
a.DoA();
break;
case ExampleB b:
b.DoB();
break;
}
}
}
And I use it in a custom multi-user serialization where I send RPC (Remote Procedure Calls) to other devices with parameters.
Extremly cropped to the necesarry it basically does
public ISendable
{
public byte[] ToBytes();
public void FromBytes(byte[] bytes);
}
// Converts any ISendable into a byte[] with the content
// typeBytes + contentBytes
public byte[] ToBytes(ISendable toSend)
{
var typeBytes = Encoding.ASCII.GetBytes(toSend.GetType().AssemblyQualifiedName);
var contentBytes = ISendable.ToBytes();
return MagicMethodToCombineByteArrays(typeBytes, contentBytes);
}
// Coonverts back from byte[] to the according ISendable
// by first reading the type, creating the instance and filling it with
// contentBytes
public T FromBytes<T>(byte[] bytes) where T : ISendable
{
MagicMethodToSplitInputBytes(out var typeBytes, out var contentBytes);
var type = Encoding.ASCII.GetString(typeBytes);
var instance = (T) Activator.CreateInstance(type);
instance.FromBytes(contentBytes);
return instance;
}

Related

Using dynamically generated type for variable declaration and assignment

Following this question, it is possible to create a type and an instance form it dynamically like this:
var type = typeof(AnimalContext<>).MakeGenericType(a.GetType());
var a_Context = Activator.CreateInstance(type);
Great.
However, what I want to do instead of creating an instance of a determined type with Activator.CreateInstance(type);is to use a dynamic created type to declare a variable, and assign an instance to my dynamically created type.
Kind of:
myDynamicallyCreatedType variableName = figuredTypeInstace;
But I cannot use the created type(var type = typeof(AnimalContext<>).MakeGenericType(a.GetType()); for declarations. Is that possible?
Edit:
Short scenario explanation where the need came up. I need to call a method that will be called from a "topManager", this topManager holds the respective instance of the types type1Manager and type2Manager that implement the same base interface IMyInterface method ImplementedMethod.
What I am trying to do, could be solved with ifs, like this:
private int HandleInstance(Type itemType, //other args) {
if (itemType == Type.type1) {
topManagerInstance.manager1Instance.ImplementedMethod(//args):
}
elseif (itemType == Type.type2) {
topManagerInstance.manager2Instance.ImplementedMethod(//args):
}
...not meaningful code
{
But, I was wondering if it could be solved handling types to avoid the ifs, like (caps used to spot the key of the question out, not to shout):
private int HandleInstance(Type itemType, //other args) {
Type managerType = itemType == Type.type1 ? typeof(manager1Type) :
typeof(manager2Type);
Type[] managerTypeArray = { managerType, typeof(int) };
var myDynamicallyCreatedType = typeof(IMyInterface<,>).MakeGenericType(managerTypeArray);
//KEY OF THE QUESTION. THIS IS WHAT I AM ASKING FOR
//assign created variable to dynamic created type to call respective method
myDynamicallyCreatedType variableName = topManagerInstance.type1Manager;
//base type. any type1ManagerType or type2ManagerType to be assigned, as
//they inherit from the same IMyInterface<,>, and the type created is
//generic
variableName.ImplementedMethod(//args):
}
It seems like you're just looking to map an enum value to a function call in a specific implementation. One way to do that is to have a factory class that handles it with a Dictionary used as a map. For example:
Given a setup something like this:
// The enum you use for mapping
public enum Thing
{
Foo,
Bar
}
// The various implementations...
public interface ISomeInterface
{
void SomeMethod();
}
public class Foo : ISomeInterface
{
public void SomeMethod() => Console.WriteLine("Foo method!");
}
public class Bar : ISomeInterface
{
public void SomeMethod() => Console.WriteLine("Bar method!");
}
Now you could have a factory that looks like this:
public class MyThingFactory
{
private Dictionary<Thing, ISomeInterface> _registry;
public MyThingFactory()
{
_registry = new Dictionary<Thing, ISomeInterface>
{
{Thing.Foo, new Foo()},
{Thing.Bar, new Bar()},
};
}
public void RunMethod(Thing thing)
{
if(!_registry.TryGetValue(thing, out var item))
{
throw new ArgumentOutOfRangeException(nameof(thing));
}
item.SomeMethod();
}
}
And call it like this:
// You may want to make this static for performance reasons since you won't recreate
// the dictionary every time
var factory = new MyThingFactory();
factory.RunMethod(Thing.Foo);
factory.RunMethod(Thing.Bar);
//Output:
//Foo method!
//Bar method!

How can I add an extension method to many classes?

I have about 1000 classes in which i need to count the number of properties of. I have the following code:
public static int NumberOfProperties()
{
Type type = typeof(C507);
return type.GetProperties().Count();
}
I could copy and paste this in to each class changing the typeof parameter but this seems a bit tedious.
Is there anyway to make an extensions method to do this by just doing var nop = C507.NumberOfProperties();?
Just to add to the answers suggesting an extension for object for completeness: you can also consider implementing an extension only for Type:
public static int GetPropertyCount(this Type t)
{
return t.GetProperties().Length;
}
and use it like this:
typeof(C507).GetPropertyCount();
The advantage is that you can get the number of properties directly from the type and do not have to create an instance first.
So you can write an extension method that uses object or one that uses type.
public static class ObjectExtensions
{
public static int GetNumberOfProperties(this object value)
{
return value.GetType().GetProperties().Count();
}
public static int GetNumberOfProperties(this Type value)
{
return value.GetProperties().Count();
}
}
Usage:
new C507().GetNumberOfProperties();
typeof(C507).GetNumberOfProperties();
However, you explicitly state two things:
I could copy and paste this in to each class changing the typeof
I have about 1000 classes
You'll likely not want to instantiate a 1000 classes or copy and paste typeof() 1000 times
In this case, you will want to read them all from the Assembly.
So something like:
typeof(SomeClass).Assembly.GetTypes().Select(x => new
{
x.Name,
PropertyCount = x.GetType().GetProperties().Count()
});
Where SomeClass is a class (doesn't matter which) where all the classes reside.
I just simply select them out into an anonymous object which contains the Types name and property count.
This:
typeof(SomeClass).Assembly
Is just a convience way to get the assembly. There are other ways.
Assembly.GetAssembly(typeof(Program)).GetTypes()
Assembly.GetCallingAssembly().GetTypes()
Assembly.Load("Some Assemble Ref").GetTypes()
You can do allsorts with the types that you find. If you select out the Type itself, you can instantiate it later using Activator.CreateInstance (if it has parameterless constuctor). You can also auto fill the properties with reflection as well.
It is impossible to have a static extension method as you imagine it. That being said, it would be possible to create a generic method in a helper class as follows.
public static int NumberOfProperties<T>()
{
Type type = typeof(T);
return type.GetProperties().Count();
}
Given a type SomeType it could be called as int n = NumberOfProperties<SomeType>().
You could make an extension method on object like this:
public static int PropertyCount(this object thing)
{
return thing.GetType().GetProperties().Count();
}
And use it on any object you like:
var x = "some string";
var numProps = x.PropertyCount();
If you want to have an extension method on object:
public static ObjectExtensions
{
public static int NumberOfProperties(this object value)
{
if (null == value)
throw new ArgumentNullException("value"); // or return 0
// Length: no need in Linq here
return value.GetType().GetProperties().Length;
}
}
...
C507 myObj = new C507();
// How many properties does myObj instance have?
int propCount = myObj.NumberOfProperties();
If you want to have an extesnion method on Type:
public static TypeExtensions
{
public static int NumberOfProperties(this Type value)
{
if (null == value)
throw new ArgumentNullException("value"); // or return 0
// Length: no need in Linq here
return value.GetProperties().Length;
}
}
...
// How many properties does C507 type have?
int propCount = typeof(C507).NumberOfProperties();
There are a couple of ways to do this that are variations of the same thing.
You can pass the Type as an argument to a method:
public static class Helper {
public static int NumberOfProperties(Type type)
{
return type.GetProperties().Count();
}
}
Which you would call like this:
// Imagine you have a class called MyClass
var result = Helper.NumberOfProperties(typeof(MyClass));
You use use the generic system in C# to make the syntax a little cleaner. That would look like this:
public static class Helper {
// Notice the argument was removed and
// the use of the "generic" syntax <T>
public static int NumberOfProperties<T>()
{
var type = typeof(T);
return type.GetProperties().Count();
}
}
And you would call it like this:
var result = Helper.NumberOfProperties<MyClass>();
You could also use "Extensions" which allow you to call it as if it was a method that belonged to your classes.
public static class Helper {
// notice the `this` keyword before the parameter
// this is what tells C# that this is an extension method
public static int NumberOfProperties<T>(this T #this)
{
var type = typeof(T);
return type.GetProperties().Count();
}
}
This will allow you to call the method like this:
var instance = new MyClass();
var result = instance.NumberOfProperties();
In this example I used the generic syntax so that it applies to any type of object. If you wanted to limit it to only objects that inherit from a specific interface or base class you would just change it from using the generic syntax to using the base class/interface. Like this:
public static class Helper {
// notice the type got changed from a generic <T>
// to specifying the exact class you want to "extend"
public static int NumberOfProperties(this MyBaseClass #this)
{
var type = typeof(T);
return type.GetProperties().Count();
}
}
As #rené-vogt mentioned you can also create the extension method so that it extends the type Type instead. See his answer in this thread: https://stackoverflow.com/a/38455233/984780
You can make a generic extension method which can apply to all types:
public static int PropertyCount<T>(this T obj)
{
return typeof(T).GetProperties().Length;
}
This will apply to all types including value types (I.E. structs) which applying to object will not. Thanks to piedar for pointing out my mistake here, applying to object does still add this extension method to value types.
If your classed can implement an interface, then you can extend that interface.
public interface IExtensible {
}
class C507 : IExtensible {
}
public static int NumberOfProperties(this IExtensible extensible)
{
Type type = extensible.GetType();
return type.GetProperties().Count();
}
That being said, having hundreds of (generated?) classes looks like a bad solution to begin with.

Use Action delegate to call correct function based on generic type

I have seen this pattern/approach used before, and I'm trying to recreate it to make some of my existing code more efficient.
The Use Case:
A complex object is retrieved from a source system. Only a subset of the information will be used by the client, so we must 'map' this complex object to a simple POCO for JSON serialization; additionally, in this mapping method, some other data formatting is done. First, we pass our complex object into a generic method that does some basic processing
// Generic Method, Entry Point for mapping
static void GenericEntry<T, TK>(string userid, string environment, DBContext context) {
.... // do stuff with userid and environment to set a context
.... // query results, which return a complex object of Type TK
// Here is where I would like to use an Action delegate to call the appropriate map
// method.. there could hundreds of objects that map and process down to a POCO,
// Currently, this logic is using reflection to find the appropriate method with
// the appropriate signature... something like:
Type functionType = typeof(DTOFunctions);
var methods = functionType.GetMethods(BindingFlags.Public | BindingFlags.Static);
var mi = methods.FirstOrDefault(x => x.Name == "MapObject" &&
x.ReturnType == typeof(T));
if (mi == null) throw new ArgumentException(string.Format("Unable to find method MapObject for {0}", typeof(TK).Name));
var resultList = new ArrayList();
foreach (var row in results)
{
var poco = mi.Invoke(functionType, new object[] { row });
resultList.Add(poco);
}
if (resultCount == -1) resultCount = resultList.Count;
return SerializeDTO(resultList, ResponseDataTypes.JSON, resultCount);
// THERE HAS TO BE A BETTER WAY STACKOVERFLOW! HALP!
}
public Class DTOFunctions {
// Mapping Method from Complex to Simple object
static SimplePOCO_A MapObject(ComplexObject_A cmplx){
var poco = new SimplePOCO_A();
.... // mapping from cmplx field to SimplePOCO field
}
static SimplePOCO_B MapObject(ComplexObject_B cmplx) {
var poco = new SimplePOCO_B();
.... // mapping from cmplx field to SimplePOCO fiel
}
}
I'm not quite sure what you're asking, but is something like this what you want?
static void GenericEntry<T, TK>(string userid, string environment,
DBContext context, Func<T, TK> conversion)
{
//....
var resultList = new List<TK>();
foreach (var row in results)
{
var poco = conversion(row);
resultList.Add(poco);
}
//....
}
Called as:
GenericEntry<ComplexObject, SimplePOCO>(userid, environment, context, DTOFunctions.MapObject)
(Note the lack of () in the argument).
It's looks like you could maybe implement the Proxy Pattern here.
Otherwise, maybe move the logic to the actual objects themselves and add a ToJSON() method in each of the ComplexObjects that knows how to serialize itself. Then append them together to make the JSON array. This will depend on what you're using to serialize the JSON, so in the example below, I've just done it manually.
The common JSONSerializable interface
public interface IJsonSerializable
{
string ToJson();
}
The Complex and simple objects:
public class ComplexObjectA : IJsonSerializable
{
public string ToJson()
{
var simpleObject = new SimpleObjectA();
// Map away
// Then serialize
return SerializeDTO(simpleObject);
}
private string SerializeDTO(SimpleObjectA simpleObject)
{
throw new NotImplementedException();
}
}
public class SimpleObjectA
{
// simple properties
}
And then entry point
static void GenericEntry<T, TK>(string userid, string environment, DBContext context)
{
// Magic happens here
var results = GetResults();
// More magic
var resultList = new List<string>();
foreach (var row in results)
{
var poco = row.ToJson();
resultList.Add(poco);
}
return String.Format("[{0}]", String.Join(resultList, ", "));
}

Property Type as Generic parameter

I'm trying to figure out how I can make a Generics call take a variable for the Type. In the call below it take a type "DAL.Account" and works fine.
var tst = ctx.GetTable<DAL.Account>().Where(t => t.Sbank == "000134");
I want to change that so that I can pass a variable in place of the "DAL.Account". Something like this but I know that won't work as you can't pass property as a Type.
ctx.GetTable<Criteria.EntityType>().Where(LinqToSQLHelper.BuildWhereStatement(Criteria.StateBag), Criteria.StateBag.Values.ToArray())
Below is the shell pieces of code I think explains what I'm trying to do. Generics is not my strong suit so I'm looking for some help. Is there anyway that I can make this happen?
//Stores a "Type" that indicates what Object is a Criteria for.
public class AccountCriteria : IGeneratedCriteria
{
...
public Type EntityType
{
get {return typeof(DAL.Account);}
}
}
//I have added a function to the DataContext called "GetTable"
// And then used it as an example in a Console App to test its functionality.
public class ADRPDataContext : NHibernateDataContext
{
...
public CodeSmith.Data.NHibernate.ITable<T> GetTable<T>() where T : EntityBase
{
var tb = new CodeSmith.Data.NHibernate.Table<T>(this);
return tb;
}
}
// console application that uses DataContext.GetTable
class Program
{
static void Main(string[] args)
{
using (var ctx = new ADRPDataContext())
{
var tst = ctx.GetTable<DAL.Account>().Where(t => t.Sbank == "000134");
}
}
}
//ExistsCommand class that uses the EntityType property of the Critera to generate the data.
public class ExistsCommand
{
private IGeneratedCriteria Criteria { get; set; }
protected override void DataPortal_Execute()
{
using (var ctx = new DC.ADRPDataContext())
{
//This was my first attempt but doesn't work becuase you can't pass a property in for a Type.
//But I can figure out how to write this so that it will work.
Result = ctx.GetTable<Criteria.EntityType>().Where(LinqToSQLHelper.BuildWhereStatement(Criteria.StateBag), Criteria.StateBag.Values.ToArray()).Count() > 0;
}
}
}
You are looking to instantiate a generic type. Some info can be found here
This is a simple example demonstrating how to instantiate a List with a capacity of 3. Here is a method that you can call to create a generic when you don't know the type:
public static Object CreateGenericListOfType(Type typeGenericWillBe)
{
//alternative to the followin:
//List<String> myList = new List<String>(3);
//build parameters for the generic's constructor (obviously this code wouldn't work if you had different constructors for each potential type)
object[] constructorArgs = new Object[1];
constructorArgs[0] = 3;
//instantiate the generic. Same as calling the one line example (commented out) above. Results in a List<String> with 3 list items
Type genericListType = typeof(List<>);
Type[] typeArgs = { typeGenericWillBe };
Type myNewGeneric = genericListType.MakeGenericType(typeArgs);
object GenericOfType = Activator.CreateInstance(myNewGeneric, constructorArgs);
return GenericOfType;
}
And here is some sample code that will show you the example method works:
List<String> Strings = (List<String>)InstantiateGenericTypeWithReflection.CreateGenericListOfType(typeof(String));
//demonstrate the object is actually a List<String> and we can do stuff like use linq extensions (isn't a good use of linq but serves as example)
Strings.Add("frist");
Strings.Add("2nd");
Strings.Add("tird");
Console.WriteLine("item index 2 value: " + Strings.Where(strings => strings == "2").First());
In your example, replace your GetTable<Criteria.EntityType>() with CreateGenericTableOfType(Criteria.EntityType). This will return a generic table of whatever type you pass in. You will of course need to implement the method properly (handle constructor args, change List to Table etc).
I think you need to change the way you're doing this slightly, and instead use generics instead of the EntityType property. Perhaps something along the lines of the following:
// Create an abstract class to be used as the base for classes that are supported by
// ExistsCommand and any other classes where you need a similar pattern
public abstract class ExtendedCriteria<T> : IGeneratedCriteria
{
public ExistsCommand GetExistsCommand()
{
return new ExistsCommand<T>(this);
}
}
// Make the non-generic ExistsCommand abstract
public abstract class ExistsCommand
{
protected abstract void DataPortal_Execute();
}
// Create a generic sub-class of ExistsCommand with the type parameter used in the GetTable call
// where you were previously trying to use the EntityType property
public class ExistsCommand<T> : ExistsCommand
{
protected override void DataPortal_Execute()
{
using (var ctx = new DC.ADRPDataContext())
{
Result = ctx.GetTable<T>().Where(LinqToSQLHelper.BuildWhereStatement(Criteria.StateBag), Criteria.StateBag.Values.ToArray()).Count() > 0;
}
}
}
// Derive the AccountCriteria from ExtendedCriteria<T> with T the entity type
public class AccountCriteria : ExtendedCriteria<DAL.Account>
{
...
}

nBuilder Testdatagenerator and Reflection

I'm using nBuilder to generate some Testdata for my application.
First I tested it and it worked fine.
An easy Example:
Customer customer = Builder<Customer>
.CreateNew()
.Build();
Creates a Object and fills all Properties automatically.
By Example, if customer Contains the attribute: name, it will fill it with name1
and so on...
Well all this works fine, but I have troubles to do that whole thing dynamically now.
What I'm doing now, is Reflection, I'm iterating through all Entities in my Class and foreach of them there should be generated some Testdata, even lookups and childlists should be filled, but thats not a problem.. My question is, how I'm using the above code with any type?
ANYTYPE object = Builder<ANYTYPE> ...
What I tried:
object entity = null; //The object/Entity
Assembly assembly = Assembly.GetAssembly(typeof(EMI_ERPContext)); //Getting Assembly
Type type = assembly.GetType(entityName); //I know the Type
//entity = Activator.CreateInstance(type); Do I must create an Instance here?
object entity = Builder<dynamic> //The above code.. Tried to put dynamic as Type, but doesnt work
.CreateNew()
.Build();
I tested with a console app (complete here), faking the classes / interfaces / methods of nBuilder.
So this works, but not tried in real context.
The method you could reuse is "TryToReflectBuilder". It could be much less verbose, but I let the "Step by step" code, as it's probably more explicit. ReflectionConsole.Test is used as the "entity to reflect".
namespace ReflectionConsole {
class Program {
static void Main(string[] args)
{
object test = TryToReflectBuilder("ReflectionConsole.Test");
Console.ReadKey();
}
public static object TryToReflectBuilder(string type)
{
//getting the assembly : not same as your way, but... that wasn't a problem for you
var assembly = Assembly.GetAssembly(typeof(Test));
//getting the entityType by name.
var entityType = assembly.GetType(type);
//The interesting (I hope) part is starting (yeah)
//get the Builder<T> type
var builderClassType = typeof(Builder<>);
//create generic argument for Builder<T> will take the type of our entity (always an array)
Type[] args = {entityType};
//pass generic arguments to Builder<T>. Which becomes Builder<entityType>
var genericBuilderType = builderClassType.MakeGenericType(args);
//create a new instance of Builder<entityType>
var builder = Activator.CreateInstance(genericBuilderType);
//retrieve the "CreateNew" method, which belongs to Builder<T> class
var createNewMethodInfo = builder.GetType().GetMethod("CreateNew");
//invoke "CreateNew" from our builder instance which gives us an ObjectBuilder<T>, so now an ObjectBuilder<entityType> (well as an ISingleObjectBuilder<entityType>, but... who minds ;))
var objectBuilder = createNewMethodInfo.Invoke(builder, null);
//retrieve the "Build" method, which belongs to ObjectBuilder<T> class
var buildMethodInfo = objectBuilder.GetType().GetMethod("Build");
//finally, invoke "Build" from our ObjectBuilder<entityType> instance, which will give us... our entity !
var result = buildMethodInfo.Invoke(objectBuilder, null);
//it would be sad to return nothing after all these efforts, no ??
return result;
}
}
public class Builder<T>
{
public static ISingleObjectBuilder<T> CreateNew()
{
Console.WriteLine(string.Format("{0} creating new",typeof(T)));
return new ObjectBuilder<T>();
}
}
public interface ISingleObjectBuilder<T> : IBuildable<T>
{
}
public interface IObjectBuilder<T> : ISingleObjectBuilder<T>
{
}
public interface IBuildable<T>
{
T Build();
}
public class ObjectBuilder<T> : ISingleObjectBuilder<T>
{
public T Build()
{
Console.WriteLine(string.Format("{0} building myself", typeof(T)));
return Activator.CreateInstance<T>();
}
}
public class Test
{
}
}

Categories

Resources