Dynamic bean instantiation (reflection???)

J

jerryau

Hi,

I am trying to dynamically create object instances based on a string
class name, and then I need to dynamically set values to these
objects, but I have no idea how to do this in C#. Here is the example
of what I need to do:

******Dog.cs******
namespace MySystem
{
public class Dog
{
private string name;

public string name
{
get { return name; }
set { name = value; }
}
}
}

******Cat.cs******
namespace MySystem
{
public class Cat
{
private string name;

public string name
{
get { return name; }
set { name = value; }
}
}
}

******SetAnimals.cs******
namespace MySystem
{
public class SetAnimals
{
string[,] animals = new string[,] {{"Dog","dogname1"},
{"Dog","dogname2"},{"Cat","catname1"}};

public IList setAnimals()
{
IList animalList = new ArrayList();

// Somehow dynamically create a new instance of an object and
add it to the animalList
// e.g. animals[0,0] is a Dog type, therefore dynamically
create a Dog class, and set the name
// for the just created Dog class taken from animals[0,1]
"dogname1"

return animalList;
}
}
}

Is what I'm trying to do possible in C#? Does anyone have any ideas
how this can be done?

Thanks,
Jerry
 
N

Niu Kun

I think the best solution for your problem can be found from the COM source.

Create a class which can spawn objects.
One method of the class take the type namestring for the class,
and inside the method contains an if-else-if-else... whick returns the
corresponding object.

Like this:

Class Spawn
{
public System.Object getInstance(string typeName)
{
if(typeName == "Dog")
return new Dog();
else if /* and so on */
}
}
 
J

Jon Skeet [C# MVP]

I am trying to dynamically create object instances based on a string
class name, and then I need to dynamically set values to these
objects, but I have no idea how to do this in C#. Here is the example
of what I need to do:

Is what I'm trying to do possible in C#? Does anyone have any ideas
how this can be done?

Sounds like you're after Spring.NET:
http://springframework.net

Jon
 
S

Stoitcho Goutsev \(100\)

Hi,

You need to use some form of reflection for this.
1. You can create a Type object for your class by calling Type.GetType and
providing the string name of the class.
2. You can use reflection to get to the constructor of the class and invoke
it or the easier way is to use Activator.CreateInstance method passing the
Type object as a parameter.
 
A

Andy

Hi,

I am trying to dynamically create object instances based on a string
class name, and then I need to dynamically set values to these
objects, but I have no idea how to do this in C#. Here is the example
of what I need to do:

******Dog.cs******
namespace MySystem
{
public class Dog
{
private string name;

public string name
{
get { return name; }
set { name = value; }
}
}

}

******Cat.cs******
namespace MySystem
{
public class Cat
{
private string name;

public string name
{
get { return name; }
set { name = value; }
}
}

}

******SetAnimals.cs******
namespace MySystem
{
public class SetAnimals
{
string[,] animals = new string[,] {{"Dog","dogname1"},
{"Dog","dogname2"},{"Cat","catname1"}};

public IList setAnimals()
{
IList animalList = new ArrayList();

// Somehow dynamically create a new instance of an object and
add it to the animalList
// e.g. animals[0,0] is a Dog type, therefore dynamically
create a Dog class, and set the name
// for the just created Dog class taken from animals[0,1]
"dogname1"

return animalList;
}
}

}

Is what I'm trying to do possible in C#? Does anyone have any ideas
how this can be done?

Thanks,
Jerry

To create the instance, I think you need
System.Activator.CreateInstance.
To set properties on the instance, you'll need to use GetType to get
the type, then get the PropertyInfo objects describing the
properties.. There's a method on PropertyInfo (SetValue, I think)
that will do what you need.

HTH
Andy
 
J

Jon Skeet [C# MVP]

Niu Kun said:
Or you can switch a class's HashCode.
That may be faster.:)

Never assume that a hashcode will be unique - they're not guaranteed to
be unique.

However, your solution also assumes that all the required types are
known at compile-time. The benefit of reflection-based solutions is
that they're very neutral - you can load any type from any assembly
(within reason).
 
T

Tom Shelton

Hi,

I am trying to dynamically create object instances based on a string
class name, and then I need to dynamically set values to these
objects, but I have no idea how to do this in C#. Here is the example
of what I need to do:

******Dog.cs******
namespace MySystem
{
public class Dog
{
private string name;

public string name
{
get { return name; }
set { name = value; }
}
}

}

******Cat.cs******
namespace MySystem
{
public class Cat
{
private string name;

public string name
{
get { return name; }
set { name = value; }
}
}

}

******SetAnimals.cs******
namespace MySystem
{
public class SetAnimals
{
string[,] animals = new string[,] {{"Dog","dogname1"},
{"Dog","dogname2"},{"Cat","catname1"}};

public IList setAnimals()
{
IList animalList = new ArrayList();

// Somehow dynamically create a new instance of an object and
add it to the animalList
// e.g. animals[0,0] is a Dog type, therefore dynamically
create a Dog class, and set the name
// for the just created Dog class taken from animals[0,1]
"dogname1"

return animalList;
}
}

}

Is what I'm trying to do possible in C#? Does anyone have any ideas
how this can be done?

Thanks,
Jerry

Jerry,

It is indeed possible... Assuming that all the types exist in the
same assembly, and are therefore loaded (in other words, there are no
dynamic loading issues to consider) then you might implement it
something like this:

using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;

namespace ConsoleApplication8
{
class Program
{

static void Main ( string[] args )
{
foreach (Animal animal in GetAnimalList ( new string[][]
{ new string[] { "Dog", "Rover" }, new string[]{ "Dog", "Rex" }, new
string[]{ "Cat", "Erica" } } ))
{
animal.Vocalize ();
}
}

private static List<Animal> GetAnimalList ( string[][]
nameTypePairs )
{
List<Animal> animals = new List<Animal>();

foreach (string[] nameTypePair in nameTypePairs)
{
Animal animal = (Animal)Assembly.GetExecutingAssembly
().CreateInstance ( string.Format ( "ConsoleApplication8.{0}",
nameTypePair[0] ), false, BindingFlags.CreateInstance, null, new
object[] { nameTypePair[1] },
System.Threading.Thread.CurrentThread.CurrentCulture, null );
animals.Add ( animal );
}

return animals;
}
}

internal abstract class Animal
{
private string name;

protected Animal ( string name )
{
this.name = name;
}

public string Name
{
get { return name; }
}

public abstract void Vocalize ();
}

internal class Dog : Animal
{
public Dog ( string name ) : base ( name ) { }

public override void Vocalize ()
{
Console.WriteLine ( "{0} Says Bark!", this.Name);
}
}

internal class Cat : Animal
{
public Cat ( string name ) : base ( name ) { }

public override void Vocalize ()
{
Console.WriteLine ( "{0} Says Meow!", this.Name );
}
}
}

I hope this is enough to get you started...
 
C

Chris Dunaway

Hi,

I am trying to dynamically create object instances based on a string
class name, and then I need to dynamically set values to these
objects, but I have no idea how to do this in C#. Here is the example
of what I need to do:

******Dog.cs******
namespace MySystem
{
public class Dog
{
private string name;

public string name
{
get { return name; }
set { name = value; }
}
}

}

******Cat.cs******
namespace MySystem
{
public class Cat
{
private string name;

public string name
{
get { return name; }
set { name = value; }
}
}

}

******SetAnimals.cs******
namespace MySystem
{
public class SetAnimals
{
string[,] animals = new string[,] {{"Dog","dogname1"},
{"Dog","dogname2"},{"Cat","catname1"}};

public IList setAnimals()
{
IList animalList = new ArrayList();

// Somehow dynamically create a new instance of an object and
add it to the animalList
// e.g. animals[0,0] is a Dog type, therefore dynamically
create a Dog class, and set the name
// for the just created Dog class taken from animals[0,1]
"dogname1"

return animalList;
}
}

}

Is what I'm trying to do possible in C#? Does anyone have any ideas
how this can be done?

Thanks,
Jerry

If you store the type name in the array instead of just "Dog", then
you should be able to do it. You can get the type name with this:

System.Type t = typeof(Dog);
string typeName = t.Name;

Then, using the System.Reflection namespace, you can call

Activator.CreateInstance(typeName)

Look at the System.Reflection namespace for more information

Chris
 
M

Marc Gravell

If you store the type name in the array instead of just "Dog", then
you should be able to do it. You can get the type name with this:

System.Type t = typeof(Dog);
string typeName = t.Name;

but doesn't typeof(Dog).Name == "Dog" ???

Once you have created the object: for setting ad-hoc properties
without a common base / interface the preferred way is probably the
component model, i.e. to set the Name property:

object obj = Activator.CreateInstance(typeName);
TypeDescriptor.GetProperties(obj)["Name"].SetValue(obj, instanceName);

You can use reflection to talk to class properties, but the above is
more flexible in many ways - i.e. you can massage the available
properties at runtime (such as how datarow view works).

Marc
 
N

not_a_commie

read the help on these topics in System:

Array.CreateInstance
Activator.CreateInstance
Type.GetType
Assembly (everything about this class)
Reflector
FieldInfo/PropertyInfo.SetValue

I think you're going to need to manually load the assembly and then
search through its types for the one you're after. Call the
Activator.CreateInstance on it. Then use the Reflector class to
enumerate a collection of FieldInfo/PropertyInfo for your instance.
 
D

DeveloperX

Hi,

I am trying to dynamically create object instances based on a string
class name, and then I need to dynamically set values to these
objects, but I have no idea how to do this in C#. Here is the example
of what I need to do:

******Dog.cs******
namespace MySystem
{
public class Dog
{
private string name;

public string name
{
get { return name; }
set { name = value; }
}
}

}

******Cat.cs******
namespace MySystem
{
public class Cat
{
private string name;

public string name
{
get { return name; }
set { name = value; }
}
}

}

******SetAnimals.cs******
namespace MySystem
{
public class SetAnimals
{
string[,] animals = new string[,] {{"Dog","dogname1"},
{"Dog","dogname2"},{"Cat","catname1"}};

public IList setAnimals()
{
IList animalList = new ArrayList();

// Somehow dynamically create a new instance of an object and
add it to the animalList
// e.g. animals[0,0] is a Dog type, therefore dynamically
create a Dog class, and set the name
// for the just created Dog class taken from animals[0,1]
"dogname1"

return animalList;
}
}

}

Is what I'm trying to do possible in C#? Does anyone have any ideas
how this can be done?

Thanks,
Jerry

You can but you might be better off approaching the problem in a
different way.

//First you need to get the type, GetType takes the name of the class
including it's namespace.
Type t = System.Type.GetType("NameSpace.Cat");
//I've defined an interface IAnimal which all my animals will
implement. You can use reflection to look for a property call Name and
then invoke it, but then you're working around the type safety that
was put in C# for a reason.
IAnimal a = (IAnimal)Activator.CreateInstance(t);
//the Interface has a Name method or a property which we can now call
on the interface for any animal.
a.Name("spot");

public class Cat : IAnimal
{
public void Name(string pName)
{
//...
}
}
public class Dog : IAnimal
{
public void Name(string pName)
{
//...
}
}
public interface IAnimal
{
void Name(string pName); //All animals have names.
}

If you need to do specific doggy things, you shouldn't take the risk
of passing a Cat to a Dog method.

You can check the type of your object in a number of ways, one of
which is:

if(a.GetType().Equals(typeof(NameSpace.Cat)))
{
Console.WriteLine("cat");
}

If you have methods that do Dog specific things they should take a Dog
as the parameter, if they do Animal specific things they should take
an IAnimal as the parameter. To reiterate there are reasons why you
might try and work around the strongly typed design of C#, but there
are probably better ways of achieving what you want to achieve.
 
J

jerryau

Thanks everyone for your replies. I have managed to get it working
using Reflection and Activator as described by Stoitcho Goutsev and
Andy. The objects I'm trying to create an instance of, are in
different Assemblies, therefore I have to search some assemblies to
find what I'm looking for, but it's working :)
I didn't want to use the "if...else" or "switch" approach as there's
to many objects to go through.

Thanks,
Jerry
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top