Peter's Gekko

Sponsors

The Lounge

News

Advertisement

Images in this post missing? We recently lost them in a site migration. We're working to restore these as you read this. Should you need an image in an emergency, please contact us at imagehelp@codebetter.com
Class variables (in Delphi) and a generic factory in C#

Last dotned meeting I had quite an interesting discussion with Thomas. He's a trainer with Oosterkamp and teaches Delphi and .net. The both of us have quite a history in Delphi. We talked about the great way you can build object factories in Delphi and we puzzled the way you could do that with C# in .net. In the weekend I took another look at it and found out that you can get pretty close in .net to the elegancy of the Delphi solution.

First I have to stress again the differences between classes and objects. A class is the grouped declaration of some variables and associated code. An object is an instance of a class. Most methods work on the instance data in an object. A static method (.net nomenclature) or class function (Delphi nomenclature) works on the class level. A typical static method is a constructor which creates new objects of its class. A class factory is different from a normal constructor, it is a (in most cases, but not necessarily) static method (of a factory class) which creates new objects. In my opinion a better name for a class factory would be object factory, but the name class factory is most commonly used. A nice thing about a factory is that it can create object of diverse types. Let's take a look at a factory which creates controls on a form. In Delphi you can implement that like this:

type
tControlClass = class of tControl;

type tControlFactory = class
   class function ConstructControl(OfType: tControlClass; OnForm : tForm): tControl;
end;

Typical is class off, here you define a type to hold class variables. Something unknown in C#. The factory method accepts a class as parameter. Typical calls to this method would be

tControlFactory.ConstructControl(tEdit, self);
tControlFactory.ConstructControl(tMonthCalender, self);

tEdit and tMonthCalender are classes found in the Delphi class library. The implementation of the ConstructControl method is quite simple

class function tControlFactory.ConstructControl(OfType: tControlClass; OnForm : tForm): tControl;
  begin
  result:= OfType.Create(OnForm);
  result.Parent:= OnForm;
end;

The method receives a class variable and makes a call to the constructor of the class. The constructor of a control in Delphi is named Create, this constructor always needs a parameter. The result of the constructor is a control. What kind of control only depends n the class passed in. The method needs no knowledge at all of all possible types of control, the only limitation is that it should descend (indirectly) from tControl.

This is pretty cool code, imagine this

procedure TForm1.Button1Click(Sender: TObject);
begin
case RadioGroup1.ItemIndex of
     0 : MaakControl(tEdit);
     1 : MaakControl(tButton);
     2 : MaakControl(tLabel);
     3 : MaakControl(TRichEdit);
     4 : MaakControl(TMonthCalendar);
     end;
end;

function TForm1.MaakControl(OfType: tControlClass): tControl;
begin
   result:= tControlFactory.ConstructControl(OfType, self);
   result.Left := TrackBar1.Position;
   result.Top := TrackBar2.Position;
end;

This is all the code you need to populate a form with controls.

The question was if you can do something like that in C#. The Delphi code is based on class variables, C# does not have them. Besides using constructors you can create objects in C# using the CreateInstance method. There is the Assembly.CreateInstance method, this method will create an object (class instance) of a class found in that assembly. There are several overloads of the method but all take a string to identify the class. This approach works but you need a reference to the assembly containing the class and I don't think a string makes the best identifier for a class you can imagine.

There are better variations of the CreateInstance method to be found in the framework. The Activator class has far more interesting overloads. The activator class is used to create new objects or get a reference to an object running remotely, it is a world on itself. Here I will dive deeper into it's GetInstance overload which takes a Type variable as its first variable. Type objects hold all metadata on another object or class. C# has no class variables but the Type class comes pretty close. Take this:

Type t = 

typeof(TextBox);

The typeof operator extracts all metadata of the argument passed, which is now in the t variable. Here I passed the TextBox class to the operator and now I have an object describing a TextBox which I can pass to a factory.

public class FactoryClass
{
  
static public System.Windows.Forms.Control ConstructControl(Type t)
   {
     
// Fiddle here
     
return Activator.CreateInstance(t) as System.Windows.Forms.Control;
   }
}

This method does exactly the same as the Delphi controlfactory we just met, it creates controls of a type determined by the Type variable passed in. The controlfactory can be used the same way.

private void button1_Click(object sender, System.EventArgs e)
{
   Control nc =
null;
  
if (radioButton1.Checked)
      nc = FactoryClass.ConstructControl(
typeof(TextBox));
  
if (radioButton2.Checked)
      nc = FactoryClass.ConstructControl(
typeof(Button));
  
if (radioButton3.Checked)
      nc = FactoryClass.ConstructControl(
typeof(RichTextBox));
  
if (radioButton4.Checked)
      nc = FactoryClass.ConstructControl(
typeof(MonthCalendar));
 

  

if (nc != null)
   {
     
this.Controls.Add(nc);
      nc.Left = trackBar1.Value;
      nc.Top = trackBar2.Value;
   }

}

(BTW, I would prefer a select statement to find out which radiobutton is checked but have not found anything like the selecteditem property of the Delphi radiobuttongroup yet in WinForms. Anybody ?)

CreateInstance will create the control using its constructor. In this scenario the default (parameterless) constructor, which is fine for a control. But what if the object to be created has multiple constructors which do need parameters ? Another overload of the CreateInstance method accepts an array of objects as its second parameter

Activator.CreateInstance Method (Type, Object[])

This array of objects forms a signature. GetInstance will search all available constructors for one whose signature matches the objects passed. If there is no constructor available which fits the pattern a MissingMethodException is thrown. In the Delphi code the Delphi compiler checked the correct signature (Create needed a parameter) in C# the runtime does the check. The Delphi factory can only create objects which are based on tControl. The C# factory will create any object described in the type parameter, as long as it can find a constructor which matches the arguments passed in. The typecast using as will set the result to null again if the constructed object was not a Control.

It would be nice to have something more in the C# language to describe types. The Type class is fine but you cannot use it to indicate that you need a more specific type. This is where the class variables in Delphi come in handy.


Posted 09-01-2003 10:54 AM by pvanooijen

[Advertisement]

Comments

John Gunnarsson wrote re: Class variables (in Delphi) and a generic factory in C#
on 09-03-2003 7:54 AM
One nice thing about .NET is Attributes, maybe this article will provide you some ideas how to implement a factory using attributes instead of class methods.


http://www.codeproject.com/csharp/factorywithattributes.asp


Have a nice day
//John

Matt wrote re: Class variables (in Delphi) and a generic factory in C#
on 09-03-2003 7:05 PM
It will be interesting to see what happens when Borland release Delphi for .NET and whether it will be a superior language to C# for Delphi developers
http://delphi.about.com/library/weekly/aa062999.ht wrote re: Class variables (in Delphi) and a generic factory in C#
on 05-18-2004 12:36 AM
Subbu wrote re: Class variables (in Delphi) and a generic factory in C#
on 12-14-2004 3:05 AM
Definitly delphi is superior to C#. Since it is only a MS version of Delphi !
David Douglas wrote re: Class variables (in Delphi) and a generic factory in C#
on 08-03-2005 11:03 AM
Have you actually run the C# code and generated controls? I duplicated the code above and I get an undefined value back from the factoryclass createcontrol method. I tried a more explicit cast and that generates a CastException.

- David
pvanooijen wrote re: Class variables (in Delphi) and a generic factory in C#
on 08-03-2005 12:01 PM
This is code copied from a working demo. And I just tested it again by copying it into a new VS 2003 project. No problem.

I can't see what went wrong in your code. Is the assembly with the desired control referenced ? What does the debugger tell you stepping through ?
usman wrote re: Class variables (in Delphi) and a generic factory in C#
on 07-30-2007 12:01 PM

Hay, i was really amused with your description that "we puzzled the way you could do that with C# in .net" as i think you can do it with more ease and control in C# . As it can enrich the powerfull library available to it of .NET and also offers you mulitple ways to do it.

pvanooijen wrote re: Class variables (in Delphi) and a generic factory in C#
on 08-20-2007 10:41 AM

@usman, right now you are right but at the moment this post was written .net was still quite new to us and we were still thinking in Delphi.

Yep, it's funny how thing schange

Ro9 wrote re: Class variables (in Delphi) and a generic factory in C#
on 01-03-2008 4:40 AM

If it's a better way to do this now a few years later could anybody provide a link?

pvanooijen wrote re: Class variables (in Delphi) and a generic factory in C#
on 01-03-2008 4:05 PM

Looking back on this after a couple of yeras I'm now fully satified with TypeOf(Class) instead of class off. And reflection in .NET is so much more powerfull than the Delphi RTTI.

sekhar svs wrote re: Class variables (in Delphi) and a generic factory in C#
on 03-19-2008 3:11 AM

1) How do we implement the single-ton design pattern in object pascal?

2)class methods in object pascal are the counter-parts of static methods in C++/Java.

But how we define class attributes(ie; static attributes in C++/Java)?

my mail id: sekhar.svs@gmail.com

Thank You

pvanooijen wrote re: Class variables (in Delphi) and a generic factory in C#
on 03-21-2008 4:32 PM

Have to delve in memory, Delphi is no longer in my toolbox.

For or an example of the singleton pattern you can take a look in the sourcecode of the VCL. Take a look at tAutoObjectFactory. Don't know about static attributes.

Felipe wrote re: Class variables (in Delphi) and a generic factory in C#
on 12-12-2008 3:13 PM

I have to say that typeof does not substitute Class Of! I'm trying to create a simple class registry that would instantiate a class descending from a base class, but since I don't have Class Of I just can't restrict which type of classes the user can register into the registry... Of course, I can throw an exception, but then I would love to make it explicity in the Add method of the registry class that it only accepts typeof(classX) or one of it's descendents! I don't have vocabulary to do that in C#, but, oh! It's so much more elegant and powerful than Delphi in so many ways...

pvanooijen wrote re: Class variables (in Delphi) and a generic factory in C#
on 12-22-2008 8:32 AM

Felipe, your story sounds like a classical example for generics. Available sunce C# 2.0. This story (5 years old..) was based on C# 0.9, at that time we didn't have generics yet.

Add a Comment

(required)  
(optional)
(required)  
Remember Me?