Instantiating types (with internal constructors) using a generic factory

A

Anders Borum

Hello!

Whilst refactoring an application, I was looking at optimizing a
ModelFactory with generics. Unfortunately, the business objects created by
the ModelFactory doesn't provide public constructors (because we do not
allow developers to instantiate them directly).

Because our business objects are instantiated very frequently, the idea of
using reflection sounds like a performance killer (I haven't done any tests
on this, but the documentation suggests that Activator.CreateInstance() is
slower than newing up objects directly).

The goal is to have a central access point for creating models (hence the
use of a factory), so that all objects are guaranteed a common state before
being handed over to other tiers.

The following sample illustrates the desired behaviour:

public abstract class CmsObjectNode
{
internal CmsObjectNode(CmsContext c) {}
}

public sealed class Page : CmsObjectNode
{
internal Page(CmsContext c) : base(c) { }
}

// User
// Role
// etc.

static class ModelFactory
{
//
public static Page CreatePage(CmsContext c)
{
return new Page(c);
}

// CreateUser
// CreateRole
// etc.

public static T CreateCmsObjectNode<T>(CmsContext c) where T :
CmsObjectNode
{
return new T(c);
}
}

...

I then thought: "Perhaps I could put the factory method on each business
type instead (just for testing purposes), and have the factory use that ..".
The following sample illustrates the factory method implementation:

public abstract class CmsObjectNode
{
internal CmsObjectNode(CmsContext c) {}
internal abstract T Create<T>(CmsContext c) where T : CmsObjectNode;
}

public sealed class Page : CmsObjectNode
{
internal Page(CmsContext c) : base(c) { }
override internal Page Create<Page>(CmsContext c)
{
return new T(c);
}
}

// User
// Role
// etc.

static class ModelFactory
{
//
public static Page CreatePage(CmsContext c)
{
return new Page(c);
}

// CreateUser
// CreateRole
// etc.

public static T CreateCmsObjectNode<T>(CmsContext c) where T :
CmsObjectNode
{
return new T(c);
}
}

I see two solutions to this problem:

1. Keep the current ModelFactory with concrete methods (although I don't
like the redundance pattern).
2. Replace requests to the ModelFactory with request to each type instead.
This provides a single access point for creating types - and the factory
method would reside on the concrete implementation.

I feel that models and factories should be seperated, but I can't see a
solution to the above.

Thanks in advance!
 
N

Nicholas Paldino [.NET/C# MVP]

Anders,

Well, I think the first thing you are going to realize is that you won't
be able to do:

new T(c);

Since the base class constructors are not automatically exposed, it
should give you a compile-time error.

I don't know that there is a good solution to this. You could use an
interface which is internal, which all the classes implement. This would be
something like ICmsObjectNode with a method called Initialize, which takes
your context, and initializes the object.

Unfortunately, this will result in you having to make the constructor of
your classes public, so you can use the new constraint. So that's not a
viable option.

You might have to ultimately rely on reflection to do this. Either
that, or create a switch statement that you have to maintain (any solution
that doesn't use reflection is ultimately going to require some specialized
code which has to be maintained when new types are created).

Hope this helps.
 
A

Anders Borum

Nicholas, thanks for the reply.
Since the base class constructors are not automatically exposed, it
should give you a compile-time error.

It does; I was simply posting the sample code to illustrate my findings.
I don't know that there is a good solution to this. You could use an
interface which is internal, which all the classes implement. This would
be something like ICmsObjectNode with a method called Initialize, which
takes your context, and initializes the object.

The goal of the ModelFactory is providing a single access point for newing
up my business objects. The initialization (or object population) process is
controlled by another part of the framework. Exposing an initialization
method using an internal interface is one way to do it, but I am simply
looking for the best solution for newing up my business objects ..

I guess this boils down to a more architectural question; it is an accepted
practice to let business objects be responsible for newing up instances of
their own type?

I see all the different implementations, but am looking for best practices.
Unfortunately, this will result in you having to make the constructor
of your classes public, so you can use the new constraint. So that's not
a viable option.

Unfortunately not. It is not up the user of the API to create new instances,
as all business objects (from a public point of view) are created in context
of another object.

Page parent = CmsHttpContext.GetPage(..);
Page child = parent.Create(..);
You might have to ultimately rely on reflection to do this. Either
that, or create a switch statement that you have to maintain (any solution
that doesn't use reflection is ultimately going to require some
specialized code which has to be maintained when new types are created).

The number of models (or types in question) in the application are approx.
15, and I have no plans on expand that number at the moment. Just for the
fun of it, I'll do a performance test using reflection (things are not
always what they seem).

Regarding the switch-statement; would you use the type of the object?

Page created = ModelFactory.Create(typeof(Page));

Again, I haven't been measuring performance but I believe reflection
operations are quite expensive. Lots of business objects have to be
instantiated all the time, so this is an absolutely crucial part of the
application.

Thanks for reading so far :)

With regards
Anders Borum / SphereWorks
Microsoft Certified Professional (.NET MCP)
 
M

Marc Gravell

I did the performance test yesterday after reading your post; by my figures,
reflection takes 80 times as long, but that still allows you to create a
good 100,000 objects in a second... This is using a generic Factory<T>
class, which (in the static constructor) pre-caches the T(Context c) ctor in
a private static field (to avoid lots of calls to GetConstructor).

Full code follows (maybe could be done better); I also get the public ctor
taking significantly less time than the others... I haven't switched the
orders to confirm it, but I suspect this is because it is the first one, and
I am filling up memory...

Marc

public class Program {
public static void Main() {
Context c = new Context();
Test<Test1>(c); // public
Test<Test2>(c); // private
Test<Test3>(c); // internal
Test<Test4>(c); // no such ctor
Test(c); // non-generic
Console.ReadLine();
}
private const int COUNT = 100000;
private static void Test<T>(Context c) { // test function;
instatiate a good few T's (using generics / reflection)
string name = typeof(T).Name;
try {
DateTime start = DateTime.Now;
for (int i = 0; i < COUNT; i++) {
Factory<T>.Create(c);
}
DateTime end = DateTime.Now;
Console.WriteLine("{0}: {1}", name,
end.Subtract(start).TotalMilliseconds);
GC.Collect(); // since throwing away lots of objects... not
recommended in production code
} catch (Exception e) {
Console.WriteLine("{0}: {1}",name,e.GetType().Name);
}
}
private static void Test(Context c) {// test function; instatiate a
good few T's (using ctor directly)
string name = "Test3*";
try {
DateTime start = DateTime.Now;
for (int i = 0; i < COUNT; i++) {
new Test3(c);
}
DateTime end = DateTime.Now;
Console.WriteLine("{0}: {1}", name,
end.Subtract(start).TotalMilliseconds);
GC.Collect(); // since throwing away lots of objects... not
recommended in production code
} catch (Exception e) {
Console.WriteLine("{0}: {1}", name, e.GetType().Name);
}
}
}
public class Test1 {public Test1(Context c) { }}
public class Test2 {private Test2(Context c) { }}
public class Test3 {internal Test3(Context c) { }}
public class Test4 {}

public class Context {}
public static class Factory<T> {

private static System.Reflection.ConstructorInfo _ctor;
static Factory() {
const System.Reflection.BindingFlags flags =
System.Reflection.BindingFlags.Public |
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance;
_ctor = typeof(T).GetConstructor(flags,null, new Type[] {
typeof(Context) },null);
if (_ctor == null) throw new NotSupportedException();
}
public static T Create(Context c) {
return (T) _ctor.Invoke(new object[] { c });
}
}
 
J

Joanna Carter [TeamB]

"Anders Borum" <[email protected]> a écrit dans le message de eHW%[email protected]...

| I see two solutions to this problem:

| 2. Replace requests to the ModelFactory with request to each type instead.
| This provides a single access point for creating types - and the factory
| method would reside on the concrete implementation.

Using the static method that takes a parameter to create an instance is just
the same as adding a parameterised constructor. Provided you don't provide a
default "noparams" constructor, then that parameterised constructor becomes
the only means to instantiate that class.

| 1. Keep the current ModelFactory with concrete methods (although I don't
| like the redundance pattern).

Unfortunately, unlike Delphi, C# doesn't have the concept of virtual
constructors and your problem is one that I have had to cope with due to
that lack of virtual constructors.

My first reaction was to design the metaclass equivalent of the Delphi
"class of" construct. In Delphi, you could do the following :

type
CmsObjectNode = class
...
public
constructor Create(c: CmsContext); virtual;
end;

CmsObjectNodeClass = class of CmsObjectNode;

Page = class(CmsObjectNode)
...
public
constructor Create(c: CmsContext); override;
end;

Then in calling code you could do this :

var
NodeClass: CmsObjectNodeClass;

Node: CmsObjectNode;
begin
NodeClass := Page;

Node := NodeClass.Create(context); // create a Page

NodeClass := OtherDerivedNode;

Node := NodeClass.Create(context); // create an OtherDerivedNode

In C#, I created a "class of" class or metaclass like this :

class MetaClass
{
private Type fClassType;

public Class(Type aType)
{
fClassType = aType;
}

public Type ClassType
{
get
{
return fClassType;
}
set
{
if (!(value.Equals(fClassType) || value.IsSubclassOf(fClassType)))
throw new TypeNotDerivedException(value, fClassType);
fClassType = value;
}
}
}

public object Create(object[] args)
{
Type[] argTypes = new Type[args.Length];

for (int i = 0; i < args.Length; i++)
argTypes = args.GetType();

ConstructorInfo lConstructor =
fClassType.GetConstructor(BindingFlags.Instance |
BindingFlags.NonPublic|
BindingFlags.Public,
null, argTypes, null);
if (lConstructor == null)
throw new ConstructorNotFoundException();

return lConstructor.Invoke(args);
}
}

This gets used with a hierarchy like this :

public abstract class Node
{
...
}

class NodeClass : Class
{
public NodeClass() : base(typeof(Node)) {}

public Node Create()
{
return Create(new object[0]);
}

public Node Create(object[] args)
{
return (Node) base.Create(args);
}

public static implicit operator NodeClass(Type type)
{
NodeClass result = new NodeClass();
result.ClassType = type;
return result;
}
}

class Page : Node
{
...
}

class Paragraph : Node
{
...
}

And the calling code does the following :

private void button1_Click(object sender, System.EventArgs e)
{
NodeClass nodeClass = typeof(Page); // create Page

Node node = pageClass.Create();

nodeClass = typeof(Paragraph); // create Paragraph

node = nodeClass.Create();
}

You can also write other parameterised constructors for the base class and
pass the expected parameters to the Create(object[] args) method.

Now the above might not be exactly what you want, but it does avoid using
Activator.CreateInstance(...) and that might help bring down the execution
time. You could also use the same ConstructorInfo technique in your factory
if you don't like the metaclass way of doing things.

| I feel that models and factories should be seperated, but I can't see a
| solution to the above.


In my experience, factories are reasonably intimately tied in to the classes
that they create.
I don't see too much problem with your internal linking of your factory with
your classes' constructors, apart from the code redundancy; What do you
think of my option ?

Joanna
 
A

Anders Borum

Marc,

You beat me to the point with the performance test - thanks for providing
the sample; it provides data for choosing the best implementation. As
previously mentioned, object initialization (or newing) is a core part of
the framework so a penaulty of ~80 times longer processing per instance is
not the right solution here.

That said other applications that are not as intensive in terms of newing
may never notice the degrade (and it does provide for a cleaner solution).
Instead of hacing

The approach provided by Joanna is also very interesting. I guess the idea
of a centralized factory is a sound architectural decision, but its simplicy
and obvious redundant patterns asks for another solution (which is why I was
looking to delegate the creation to the types instead, possibly with a
similar approach as provided by Joanna).

This is the output of your test (in ms):

Test1: 187,5
Test2: 796,875
Test3: 625
Test4: TypeInitializationException
Test3*: 0
Full code follows (maybe could be done better); I also get the public ctor
taking significantly less time than the others... I haven't switched the
orders to confirm it, but I suspect this is because it is the first one,
and I am filling up memory...

Tried switching with no effect.

[ code clipped ]

With regards
Anders Borum / SphereWorks
Microsoft Certified Professional (.NET MCP)
 

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