CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Peter's Gekko

public Blog MyNotepad : Imho { }

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.



Comments

Matt said:

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
# September 3, 2003 7:05 PM

http://delphi.about.com/library/weekly/aa062999.ht said:

# May 18, 2004 12:36 AM

Subbu said:

Definitly delphi is superior to C#. Since it is only a MS version of Delphi !
# December 14, 2004 3:05 AM

David Douglas said:

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
# August 3, 2005 11:03 AM

pvanooijen said:

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 ?
# August 3, 2005 12:01 PM

usman said:

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.

# July 30, 2007 12:01 PM

pvanooijen said:

@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

# August 20, 2007 10:41 AM

Ro9 said:

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

# January 3, 2008 4:40 AM

pvanooijen said:

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.

# January 3, 2008 4:05 PM

sekhar svs said:

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

# March 19, 2008 3:11 AM

pvanooijen said:

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.

# March 21, 2008 4:32 PM

Leave a Comment

(required)  
(optional)
(required)  

Enter the numbers above:
Add
Check out Devlicio.us!

This Blog

Syndication

News