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

Peter's Gekko

public Blog MyNotepad : Imho { }

September 2003 - Posts

  • Blogging articles

    The dnj site allready contains a huge amount of tutorials and other stuff, so what would be the use to start publishing articles in a blog ? I think a good reason would be feedback to check and improve the content. You can discuss a publication in the forums but it is hard to update an article already published. The dnj people are doing a great job in checking and formatting all submissions which make the dnj article library a coherent whole, but when it's published it is published. An article published in the author's weblog can be commented upon and can be updated by the author at any time. To try this I have published an article on my log, in the category Public beta on "Passing data in and out of web services using (typed) xml (-datasets)".  It is public beta which stands for please report any comments and please don't mind sloppy language.

  • To RPC or to WSE ?

    MSDN tv is great. Over there you can watch very interesting presentations on very interesting material. The image quality is good enough to read what is being typed. The sound is so-so, you have to turn up the volume quite a bit to understand what the speaker is saying. Any questions from the audience are just a mumble in the background. Anyway, not as bad as some other sites where the sound is distorted, just be fast enough to turn down the volume at the end before the end tune will (sound-)blast(-er) you away.

    In case you havn't seen Don Box yet : it's really great. Talking on services Don stresses that a service consumer wants to know as little about the (web) service as possible. The world view of consumers is not that of a hard-core programmer like you and me and consuming services should not be described to them as making an RPC call where, thanks to the richness of XSD schema, the parameters to a call  can be typed as precise as int or a long. Not quite the subtleties the average service consumer is interested in.

    Have you seen Keith Ballinger in his presentation on WSE 2.0 ? Keith does like RPC and shows wonderful things you can do with it. One of the most interesting parts in his story is where he describes RPC like sending a message and expecting a response message almost immediately. When this response starts taking longer the consumer can invoke the service asynchronously and wait in the background for the service to complete. But what if it takes days before a response is ready ? In comes the message queue. The request message (RPC call requesting a result) is posted in the queue. Compare it to sending an email message to the outbox. When will the the reply message arrive ? Maybe a reply is not even needed. The notion of a procedure call has disappeared, the only thing left is a request in the form of a message. This message will be read by some piece of software, which will send a reply when necessary.

    You can download the WSE 2.0 as a "technology preview". I am going to toy with it; it looks a little like the building bricks for parts of Indigo. Well... the closest you can get at the moment.

    Blog on,

    Peter

  • FeedDemon: absolutly great !

    I was still looking for a news-aggregator. Having tried everything I could get my hands on, RSS Bandit was the only one which had survived. I learned to live with its pecularities, the most annoying being its ability to forget time after time the channels I want to read and the post I had allready read. Everytime I switched on my machine after a standby or hibernation RSS had lost track. Something supposed to be fixed in the version I run..

    From the PDC bloggers page I followed the link to FeedDemon, another news-agregator. Installed and liked it from the very first moment. The UI is cool and FeedDemon it has a rich set of features. To mention just two of them :

    • A fully functional browser included. This browser does understand the back and forward buttons of my mouse. (Most included browsers don't)
    • When you use the browser to navigate to a log page and click the OPML link FeedDemon pops up a dialog and after a few clicks you're up and reading the blog. Like the infamous gotdotnet blog.

    When it comes to crosslinks FeedDemon follows a different approach. Instead of listing the comments it was able to find it doesn't show anything in the list of posts. But when you click a post it will show the full post page, including the comments, in the browser. I can live with that.

    Highly recommended !

    Blog on,

    Peter

  • Getting ready for the PDC

    My first reason for going to the PDC is that I just love to hear good stories on software development. The upcoming Whidbey has such an enormous amount of fascinating features, I just have to hear these from the people who created them. My second reason for going is writing on software development. As I am doing a book on "OOP with Whidbey" (for APress) the PDC is the place to be. I am not a part of the happy few who already have a copy of Whidbey running, my main source is "radio trottoir" and all other fragments floating around on the web. The PDC session overview looks like a feature list of .net 2.0. There is far to much to follow everything, I have to make a choice. Not just for sessions, but for subjects as well. I ordered the conference DVD so I'll be able to watch all tracks I didn't attend some time later back home.

    My main track will be "Indigo and surroundings". What is Indigo ? To Don Box it is a state of mind, to me it looks like a way to route (xml-based) information through (inter-)networks at its own pace. Working with web services in .net 1 you have the choice to invoke a web-service synchronous and a-synchronous. And  that is about it. Reading through the session abstracts I see things like Building Occasionally-connected, Async Client Applications, and "Indigo" brings together the best of .NET Remoting, MSMQ, ASMX and .NET Enterprise Services . New in this context are message queues. The 2 version of compact framework will also support these. I had been working with mq's in net 1, it proved to be a good way to store (xml data) messages on a system until the receiver is ready for them, adding a new level of asynchronous operation to apps. All of that will be included in Whidbey. I will have to do quite an overhaul on my material on that. As quite a part is now in the framework I have room to cover more of the new stuff. My mind is in a certain state now, I'll see on the PDC how well the color matches. Just can't wait.

    Blog on

    Peter

  • Spamming a weblog

    This may sound ridicilous but my blog got spammed. A comment on a post of last august by Viagrx consited of a large list of url's pointing to the usual rubbish. Handy that delete comment linkbutton.
  • Smartnavigation not so smart when it comes to a Response.Redirect

    This post is about something which is widely found on the net, you will find many hits with google on the (at first sight) unlogical combination of Smartnavigation and Redirect. Nevertheless it kept me busy for some time. There seemed to be no relation between the two things untill I found out what was going on. Maybe this will save some of you a little time.

    In an application I have implemented a general error handling routine. It collects some information and redirects the application to an error page which sums up all. Everything worked like a snap up till last version, which only produced blank screens. In this last version I had also set the smartnavigation property of the pages and that was exactly what messed up my error handling. Smartnavigation takes care of a couple of things

    • Prevent all postbacks of the same page building up in the navigation history of the browser
    • Eliminate "navigation flash"
    • Persist scroll position over postbacks
    • Persist focus over postbacks

    The last two points are not always what you want. Consider changing the selected item in a datagrid from an item in the top of the list to one in the bottom. More on that in an upcoming article. But the first point is reason enough to switch smartnavigation on. What the docs don't tell you (but what you could have guessed) is that smartnav fiddles with the context of your response. The Redirect method of the response no longer works, breaking my error handler. The docs advise you In most circumstances, do not set this property in code, but that was exactly the way to repair my errorhandler. In the snippet p is the page on which the error occured, the code will redirect the app to newURL, a string which contains the URL of the error displaying page. The info is in the querystring.

    p.SmartNavigation =

    false;
    context.Response.Redirect(newURL,
    true);

    Smartnavigation does not seem to have an influence on the request. A member of the request is an URLreferrer property, it is the URL your app last visited before arriving on this page. The first time the page is requested it is the page you came from but after a postback it is always the same as the URL of the page itself. With and without smartnavigation. Considering the first of the reasons to use smartnav it might seem logical that the property would keep pointing at the last different page visited. But it's hard to mimic state.

    Blog on,

    Peter

  • Changing the visibility of a class member and base classes in the framework

    Working on a custom web-control I have been struggling a little with the visibility of class members. What I wanted to do is define functionality in a base class, keep that hidden and publish parts of it in descendent classes. Take this example :

    public abstract class Class1
    {
      
    public Class1()
       {
       }

      

    protected virtual string m1()
       {
         
    return "One";
       }

      

    protected virtual string m2()
       {
         
    return "Two";
       }

    }

    The class is declared as abstract to prevent instances of it being created. The functionality is in the two methods, they are both protected to hide them. Two new classes are based on this class, one will only expose the method m1, the other will only expose m2. The easiest approach would be to create new methods which use the protected methods of the base class. But I want to keep the existing method names and signatures. The first approach exactly describes my intentions :

    public class Cd1 : Class1
    {
      
    public override string m1()
       {
         
    return base.m1();
       }

    }

    But this will not compile. You cannot change the visibility of a member. The workaround is to use the new modifier to hide the inherited method. 

    public class Cd1 : Class1
    {
      
    public virtual new string m1()
       {
         
    return base.m1();
       }
    }

    public class Cd2 : Class1
    {
      
    public virtual new string m2()
       {
         
    return base.m2();
       }
    }

    The good thing is that I can still use the implementation of the base class in the new method. By declaring the method as virtual I can override the method again in descending classes

    public class Cd11 : Cd1
    {
      
    public override string m1()
       {
         
    return base.m1() + " derived";
       }
    }

    Working this way was inspired by Delphi (again, breaking up is hard to do). In Delphi you can change the visibility of members. All you need to do is re-declare a protected member as a published property. Published is Delphi speak for a reflectable public member. The VCL, Delphi's class library, uses this technique a lot. It contains for most controls a custom base class. All functionality of the control is defined in there. Building the control boils down to publishing those methods you need in the control.

    The FCL does not have that kind of base-classes. I was creating a link-button and wanted to hide the commandname property. In Delphi I would have published selected properties from the custom linkbutton base class, but the FCL LinkButton inherits directly from the WebControl class. If I used that as a base class would mean I would lose all the desired inherited Linkbutton functionality as well. As a second approach I tried to override the CommandName property, alas it is not virtual. So I had to make up a story to turn this "bug" in a feature.

    I prefer the C# syntax to change the visibility of a member. It does take a little more typing than the Delphi way (usually it is the other way round) but is clearer and more flexible. But I would love to have something like the custom base classes in the framework.

    Blog on.

    Peter

  • Crash testing Server 2003, aka system maintenance

    Perhaps not a very interesting thing for a blog but I have spent some time on "system maintenance" leading to some thing I want to share with you.

    I have a former PC running Windows 2003 server. It is a 450 Mhz PII with 512 Mb of RAM. Figures you would reject for a workstation but 2003 server (enterprise) runs like a charm. For a SOHO development environment it makes a perfect web/SQL server. Booting takes some time but when it is running performance is perfect. As the machine is not needed on a 7*24 base I switch it off regularly. Instead of a system shutdown I hibernate the system from a remote desktop. Always worked like a charm, never let me down, I even upgraded from beta to release using a remote desktop and a remote DVD player.

    Yesterday I did something really stupid. In the machine was still an unused TV-card (Miro thing, more on that later), I removed the card to transfer it to a workstation. The stupid thing was that I had, as always, hibernated the system. Switching it on gave a very clear error message : "memory signature changed, system will not restore from hibernation". The only option was to reboot but the thing had gone really bananas. Every booting attempt led to an automatic reset somewhere in the booting process. I reset the bios of the PC and unplugged the tapestreamer, being the 3d IDE device. 2003 booted, asked in a dialog why the system had unexpectedly crashed (you can pick a reason, power failure is an option, stupidity isn't),  took quite some time to rebuild the Active Directory Indices, reported that the clock was wrong and that the tapedrive wasn't working. I set the clock, shut down once more to connect the tape, rebooted and now my server is back in bussiness without any notable damage. I was already very impressed by the performance and reliability of 2003 (not to mention the functionality), after this experience I am fully convinced.

    The Miro card was a disaster. It was originally designed for W98, NT 4. On the Pinnacle (the company who bought Miro) site XP software, PCTV version 5.5, can be downloaded. Which is presented as an upgrade on version 4.0. But I didn't have a 4.0 neither did the Pinnacle site. It took me 15 pages of Google to find a 4.0. Guess what happened when I finally got to installing the 5.5 upgrade: "Please uninstall the previous 4.0 version before installing this one" Aaargh.... And the bottom line was that the software did not even work, it reported an interrupt conflict. The device manager didn't agree. I left it for what it was, had real work to do.

    My development machine needed some attention to. Quite often it almost froze while the disk drive was rattling like hell. Something the XP disk-defragmenter could not cure. I downloaded a trial of disk-keeper. Marvelous tool. It is fast, in 10 minutes my system was running like a fresh install. And it is very easy to use, the feature I like best is the "screen saver mode". When your screensaver pops up disk-keeper will defragment your disk. Simple easy and very efficient. Absolutely recommended.

    The last thing of "system-maintenance" I did was polish up my web-log. There are a lot of skins you can choose, I took the dnj-skin. Great to be junkie !

    Blog on.

    Peter

  • Weaving the web

    I still believe the best form of communication is two way, including in weblogs. It is nice that readers can comment to posts in a weblog. For years I have lived in newsgroups, being a heavy poster and replyer. Web-logs seem a little different from newsgroups, in a weblog you post something you want to tell about, in a newsgroup you post a question you want others to tell more about. I don't see this distinction, a post in a weblog could be an interesting start to a discussion. But the problem is how to get that organized, still nothing beats the tree-formed threads in a newsreader like outlook express. Last week I took a look at a web based newsagregator Junkie XL had mentioned. The user interface of Nifty portal is quite astonishing, it doesn't look or feel like a web-app at all. But on the content side it has major drawbacks : you can only subscribe to feeds served by Nifty Portal. Not to mention feedback possibilities. I keep on looking.

    For the time being I will react to feedback over here. Delphi really is still a hot item. Joseph, you are not a blog pest at all but the Pascal for .NET you are refering to does not have the rich possibilities of Delphi's Object Pascal. Was it D(anny) Thorpe who pointed to this ? Must be, he really knows what a great language Delphi is. Next week it will be 20 years ago that Turbo Pascal saw the market. In the Netherlands there will be a party to celebrate (link in Dutch) that. I'll be there.

    My comments on the datareader also rose some questions. Neil brought up that I only investigated the difference in execution speed and not the memory impact of a datareader. The ANTS profiler does not provide any statistics on that, maybe the profiler Joseph (him again) mentions does give any insight. Have to try that.

    To conclude I do have to mention that my article on the datagrid is now online. But I guess you have already seen that on the dnj home page. Thanks a lot Donnie ! The sequel is almost ready.

    Blog on,

    Peter

     

  • Profiling a datareader

    It is hard to be original on the web, everything has been said before. In my blog on datareaders I talked about some performance tests I had done on a datareader. Both Joseph Cooney in a response and Grant Kilian in his blog point to an extensive article which compares the performance of different data access methods in a real world situation, including using a datareader. One of their conclusions is that a datareader only pays off when you are accessing larger amounts of data. The main conclusion is that you should test your own situation to find out what works best.

    A nice way to test the performance is the ANTS profiler. (Yes, I do visit the dnj sponsors). You can download a fully functional trial which works for 14 days. Using ANTS is easy. Start it, run your app and see the results in ANTS. This also works for asp.net apps. Tell ANTS you are going to profile a web-page (or service). Start your browser, run the aspx'-es and when you're finished click the "Stop profiling" button. The results in ANTS are very detailed, you can drill down to the sourceline. After reorganizing my code I used ANTS to find the bottleneck's in data access performance. In this screenshot you can see some of the results.

    What can be seen from this ? Binding the data to the grid is a fraction faster using a reader. But it is a pity you cannot design your grid, you do need a dataset to do that. The other thing taking time is the Fill operation of the data-adapter. But in the real world these differences are academic. The "user-experience" in both approaches is the same. On my overstressed machine, running IIS and sql server local, It takes about a second to build up the huge page, there is no human noticeable difference.

    The article mentions a drawback of datareaders which can prevent an application from scaling. As long as you don't close a datareader there is a connection to the database which cannot be used by other code. The authors tested the implications of this by limiting the number of connections and setting a small delay between the execution and the closing of the reader. The result was that the dataset soon outperformed the datareader as the number of requests grew. So a datareader does not scale that well.

    Which brings me to one final point worth discussing. How to handle database connections in a web page in general ? What I do is open the connection in the page_load event and close it in the page_unload event. The nice thing is that the page_unload event always gets fired, also when an exception is thrown on the page. And my connection pool will not get polluted with unused connection waiting to time out. More on all of this in an upcoming article (on the datagrid) which is at the moment still somewhere on Donny's or Doug's desk.

    Blog on !

    Peter

  • The spirit of Delphi (for .net)

    Last week I talked a little on Csharpbuilder and Delphi in my blog. Great to hear that there a lot of other (ex) Delphi people around who do like to work with C# and .NET. In my blog I discussed class variables in Delphi and a workaround for them in C#. John Gunnarsson, another nice guy, pointed me to an article on using attributes in a factory. In there attributes are used as a workaround for another thing Delphi does have and C# does not. In Delphi a static (or class- in Delphi nomenclature) method (including a constructor) can be virtual or even abstract. In .NET you are stuck with the class methods of your ancestor class. And there are more things Delphi has which C# has not. Like the implements keyword. In a Delphi class which implements a couple of interfaces you can declare a member which will take care of the implementation of one of those interfaces. After adding implements ImyInterface you are ready with that interface. In C# you have to write stubs for every method of the interface to redirect the call to the member. Which is a little more work. I should mention that the implements keyword in Delphi does not work in all scenarios, sometimes you end up writing the stubs yourself after all.

    The spirit of Delphi is still alive. C#builder does not seem to be able to pull Delphi people back to Borland, maybe Delphi for .NET can do that. There is a (beta) Delphi for .NET compiler. The language needed some additions and modifications to work under .NET. One of the main problems is backwards compatibility, Delphi has a history of years, projects created with earlier versions should work in the .net version as well. Borland's plan is to release Delphi for .net with a new IDE (Octane, aka Delphi 8). What that IDE is going to look like is still a mystery, what I have seen in C#builder does not make me very optimistic. I wish they concentrated on a Delphi.NET for VS.NET but I don't think the marketing department of Borland will agree on that. I would buy a copy.

  • Datareaders or typed datasets ?

    Is a datareader faster ?

    There are several ways to get to your data in a .net application. You can use a data-adapter to fill an XML-dataset or you can directly read your data using a datareader. A lot of code sample use datareaders, the main reason presented is the (assumed) performance. The main advantage of an XML-dataset is that it can be strongly typed to describe the data you are dealing with. So there seems to be a payoff between performance and ease (and quality) of coding. In the Apress database forum I found a very interesting thread on making datareader code easier to use. Working hard on an Apress title myself, this lead me to some investigations. My main question was, preferring typed datasets, if using a datareader is really that much faster.

    As a first test I built a Winform app. On creation the form opens a sqlconnection. On the form is a data-adapter, in its select statement it selects the title field from the titles table in SQl-server's pubs database. From the data-adapter I generated a DataSetTitles. This dataset is not in the designer, I have to create an instance to use it. Two different methods read the data to fill a listbox on the form.

    Using a typed dataset :

    private void fillFromDataSet()
    {
       DataSetTitles ds =
    new DataSetTitles();
       sqlDataAdapter1.Fill(ds.titles);
      
    for (int i = 0; i < ds.titles.Count; i++)
          listBox1.Items.Add(ds.titles[i].title);
    }

    And using a datareader :

    private void fillFromDataReader()
    {
       System.Data.SqlClient.SqlDataReader dr;
       dr = sqlDataAdapter1.SelectCommand.ExecuteReader();
      
    while (dr.Read())
          listBox1.Items.Add(dr.GetString(dr.GetOrdinal("title")));
       dr.Close();
    }

    The datareader uses the selectcommand of the data-adapter. I learned the construction dr.GetString(dr.GetOrdinal("title")) from Pete Wright in the Apress forum. (Read these, there are a lot of interesting thing happening at Apress) The statement is nice but the fact that you have to identify the fieldname in a string always gives me an itch. My mantra is "Allways used strong typed objects". I prefer ds.titles[i].title, but that cannot be done using a reader.

    Next I wrote some code to compare the speed of the two different ways to get to the data :

    private void button1_Click(object sender, System.EventArgs e)
    {
       listBox1.Items.Clear();
       DateTime start = DateTime.Now;
      
    for (int i= 0; i < numericUpDown1.Value; ++i)
       {
         
    if (checkBox1.Checked)
             fillFromDataReader();
         
    else
             fillFromDataSet();
       }
       DateTime stop = DateTime.Now;
      
    int elapsed = (int) (stop.Ticks - start.Ticks);
       label1.Text = elapsed.ToString();
    }

    In the actual code there are some more things to do statistics, but this will give you an idea.

    The results :

    • The time needed to get the data varied quite a lot in both approaches
    • The first fill is always slower
    • Using a data-reader in this situation is on the average only 10% faster

    As a second test I built a web application. This time I read over 300 rows of 8 columns. Quite different data. The data read in is used to populate a datagrid.

    Using a datareader:

    System.Data.SqlClient.SqlDataReader dr;
    dr = sqlDataAdapter1.SelectCommand.ExecuteReader();
    DataGrid1.DataSource = dr;
    DataGrid1.DataBind();
    dr.Close();

    And using a dataset

    DataSetMOC ds =

    new DataSetMOC();
    sqlDataAdapter1.Fill(ds.ProjektChecklistItem);
    DataGrid1.DataSource = ds;
    DataGrid1.DataBind();

    The result were quite comparable to the winform situation. Again a lot of variation and again the datareader performing somewhere about 10% better.

    What good are datareaders ?

    Based on this sloppy test (please correct me if I did something wrong) my conclusion would be that it does not really pay off to use datareaders. Some fragments of your code will run a little faster. Browsing on the net you will find resources claiming a greater speed gain than I describe here, but (some of) these resources compare an oleDBdatAdapater with a sqlDataReader. Here I compared a sqlDataReader with a sqlDataAdapter.

    In fact the dataAdapter is using a datareader internally when it is executing the Fill method. Using a data-adapter to fill typed datasets in your own code instead of a datareader gives you the possibility to write clearer and better code. GetOrdinal("tittle") is a bug you will not see until your app is running, ds.titles[i].tittle is something the compiler will see immediately. This is a gain in speed and quality of development I am quite willing to pay the (apparently) small performance overhead for.

    Note : There are two reasons why this story does not apply to the compact framework. Besides resources being more expensive there, the compact framework has no knowledge of typed datasets at all.

  • 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.

More Posts