Can I use typeof() to make new objects?

  • Thread starter Thread starter Einar Værnes
  • Start date Start date
E

Einar Værnes

Hi.
I am trying to programatically decide which type a new object should have,
but the typeof-function is apparently not the answer, as the following code
will not compile.

class AbstractClass:Object { }

class DerivedClass1 : AbstractClass { }

class DerivedClass2 : AbstractClass { }

static class Program
{
static void Main()
{
AbstractClass a,b,c;
a = new DerivedClass1();
b = new DerivedClass2();
if (some_condition)
c = new (typeof(a))();
else
c = new (typeof(b))();
}
}

How can implement this?

Best regards
Einar Værnes
 
Hi,
Hi.
I am trying to programatically decide which type a new object should have,
but the typeof-function is apparently not the answer, as the following code
will not compile.

class AbstractClass:Object { }

class DerivedClass1 : AbstractClass { }

class DerivedClass2 : AbstractClass { }

static class Program
{
static void Main()
{
AbstractClass a,b,c;
a = new DerivedClass1();
b = new DerivedClass2();
if (some_condition)
c = new (typeof(a))();
else
c = new (typeof(b))();
}
}

How can implement this?

Take a look into the System.Reflection namespace. With typeof you will
get a Type object. The Assembly type has a CreateInstance method, which
will create a new object of a type:

AbstractClass myObject;
// ...
Type t = typeof(myObject);
Assembly a = Assembly.GetAssembly(t);
AbstractClass newObject = a.CreateInstance(t.FullName);
// ...

There are several signatures for Assembly::CreateInstance. So you can
pass arguments to the constructor, for example.


Btw and not concering your question, I find it confusing to have a class
that is named "AbstractClass" but is not declared abstract. But that
just a metter of "taste" :)

HTH,
Tobi
 
Well, you already created the instances? At a simple level, the
following should suffice:

AbstractClass c;
if(some_condition) {
c = new DerivedClass1();
} else {
c = new DerivedClass2();
}

There are other approaches:
* Activator.CreateInstance({various overloads})
* from reflection you can obtain and invoke the constructor
* you can use generics with the ": new() " (and perhaps " :
AbstractClass") clause(s)
* you can perhaps use a factory interface on existing instances

Can you explain a little more about the scenario, to identify a likely
candidate?

Note that typeof() works on type-definitions, not instances; in your
code you would use a.GetType() and b.GetType() to obtain the Type,
which can be used to create *additional* instances.
 
Tobias said:
AbstractClass myObject;
// ...
Type t = typeof(myObject);
Assembly a = Assembly.GetAssembly(t);
AbstractClass newObject = a.CreateInstance(t.FullName);
// ...

Argh, just saw an error:

Type t = myObject.GetType(); // not: Type t = typeof(myObject);

That would be correct, sorry.

Tobi
 
Einar said:
Thank you!
This did the job (with an additional typecast).

yes, the CreateInstace return object must be casted :o)
You should add some exception handling around the code, especially, if
you create the object from a type name that is read from the configuration.
Einar Værnes
AbstractClass newObject = (AbstractClass)a.CreateInstance(t.FullName);
 
Thanks for your answer, what I really want is to use a copy constructor,
like this:

public abstract class AbstractClass:Object { }

public class DerivedClass1 : AbstractClass
{
public DerivedClass1(){}
public DerivedClass1(AbstractClass a)
{
//some implementation
}
}

public class DerivedClass2 : AbstractClass
{
public DerivedClass2(){}
public DerivedClass2(AbstractClass a)
{
//some other implementation
}
}

static class Program
{
static void Main()
{
AbstractClass A = new DerivedClass2();

// Make a backup copy of object A (which in principle can have
any type derived from AbstractClass)
AbstractClass C = new (A.GetType())(A);
}
}


I can now (thanks to Tobias Schröer) create a new class of same type as A :
AbstractClass C =
(AbstractClass)Assembly.GetAssembly(A.GetType()).CreateInstance(A.GetType().FullName);
but this will not make a copy of object A, just a new object instance of the
same class as A.
Can I use CreateInstance to activate the copy constructor of the appropiate
class?


Best regards
Einar Værnes
 
Einar said:
Thanks for your answer, what I really want is to use a copy constructor,
like this: [..]

I can now (thanks to Tobias Schröer) create a new class of same type as A :
AbstractClass C =
(AbstractClass)Assembly.GetAssembly(A.GetType()).CreateInstance(A.GetType().FullName);
but this will not make a copy of object A, just a new object instance of the
same class as A.
Can I use CreateInstance to activate the copy constructor of the appropiate
class?

See the System.IClonable interface and Object::MemberwiseClone(), that
should help.
Maybe you should google on cloning mechanisms. Depending on the data an
object contains (primitive or complex), some algorithms would be better
than others. E.g., serializing and deserializing an object can be used
for cloning.

Tobi
 
Since you seem to be calling the current type's own copy constructor
(i.e. if the type to be copied is "ClassA", you appear to be calling
"new ClassA(a)", how about just using a neatly typed ICloneable
implemenation?

using System;
public abstract class AbstractClass : ICloneable {
public AbstractClass Clone() { return DoClone(); }
object ICloneable.Clone() { return DoClone(); }
protected abstract AbstractClass DoClone();
}

public class DerivedClass1 : AbstractClass
{
public new DerivedClass1 Clone() { return
(DerivedClass1)DoClone(); }
protected override AbstractClass DoClone()
{
return null; // provide implementation
}
}

public class DerivedClass2 : AbstractClass
{
public new DerivedClass2 Clone() { return
(DerivedClass2)DoClone(); }
protected override AbstractClass DoClone()
{
return null; // provide implementation
}
}
 
It seems to get quite complicated to solve a apparently simple problem using
a copy constructor.

I have now moved the copy constructor code into a virtual
CloneFrom(AbstractClass a) - methode.
This implementation now does the job well enough for me:

namespace WindowsApplication1
{

public abstract class AbstractClass : Object
{
public int test_variable;
public abstract void CloneFrom(AbstractClass a);
}

public class DerivedClass1 : AbstractClass
{
public string teststring = "?";
public DerivedClass1() { test_variable = 1; }
public DerivedClass1(DerivedClass1 a) { CloneFrom(a); }
public override void CloneFrom(AbstractClass a)
{
DerivedClass1 c = (DerivedClass1)a;
test_variable = c.test_variable;
teststring = c.teststring;
}
}

static class Program
{
static void Main()
{
AbstractClass a;
a = new DerivedClass1();
a.test_variable = 100;
((DerivedClass1)a).teststring = "a";

// Make a backup copy of object a (which in principle can have
any type derived from AbstractClass)
AbstractClass d =
(AbstractClass)Assembly.GetAssembly(a.GetType()).CreateInstance(a.GetType().FullName);
d.CloneFrom(a);
((DerivedClass1)a).teststring = "a changed";
a.test_variable = 200; // Now test a.test_variable=200

// Restore a from backup
a.CloneFrom(d); // Now test a.test_variable=100
}
}

}
 
"Einar Værnes" <[email protected]> a écrit dans le message de (e-mail address removed)...

| Thank you!
| This did the job (with an additional typecast).

Einar

I really would recommend that you use the Clone method rather than using
reflection, there can be quite a speed difference if you need to create lots
of objects.

public abstract class Base : ICloneable
{
public abstract object Clone();
}

public class DerivedClass1 : Base
{
public override object Clone()
{
return new DerivedClass1();
}
}


public class DerivedClass2 : Base
{
public override object Clone()
{
return new DerivedClass2();
}
}

static class Program
{
static void Main()
{
Base a,b,c;

a = new DerivedClass1();

b = new DerivedClass2();

if (some_condition)
c = (Base) a.Clone();
else
c = (Base) b.Clone();
}
}

This is known as the Prototype pattern and is very useful for fast creation
of instances based on a prototype instance.

Joanna
 
"Joanna Carter [TeamB]" <[email protected]> a écrit dans le message de
%[email protected]...

| I really would recommend that you use the Clone method rather than using
| reflection, there can be quite a speed difference if you need to create
lots
| of objects.

I forgot that this can also help with using a copy constructor :

public class DerivedClass1 : Base
{
public DerivedClass1(DerivedClass1 other)
{
// copy private members from other
}

public override object Clone()
{
return new DerivedClass1(this);
}
}

public class DerivedClass2 : Base
{
public DerivedClass2(DerivedClass2 other)
{
// copy private members from other
}

public override object Clone()
{
return new DerivedClass2(this);
}
}

Joanna
 
Back
Top