473,386 Members | 1,766 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,386 software developers and data experts.

Making sure static constructors have been called

I want to create a class with a static property as follows:

class MyClass
{
private static List<MyHandlerRegisteredHandlers =
new List<MyHandler>;
}

I then want to be able to create descendants of the MyHandler class
which will register themselves using a RegisterHandler method, which
basically adds one and only one instance of such classes to the static
list of RegisteredHandlers.

Each MyHandler will be able to deal a particular kind of object and will
have a bool HandlesObject(object aObject) method that returns true/false
to say wether it's capable of dealing with that object or not.

Finally, I want to be able to loop through an array of objects, check to
see if there is a MyHandler registered for each and, if so, call
MyHandler.DoSomething(theObject);

Initially I figured I could have each of the MyHandler descendant
classes implement a static constructor as follows:

class SomeObjectHandler : MyHandler
{
static SomeObjectHandler()
{
MyClass.RegisterHandler(new SomeObjectHandler());
}
}

However, it seems static constructors are only guaranteed to be called
sometime after the program starts and before an instance of the object
that they apply to is instantiated. In my case, the only instance of
SomeObjectHandler that will be instantiated is the one that gets
instantiated in it's own static constructor... which means that the
approach above isn't going to work.

In Delphi/ObjectPascal (which I used to use) each code unit can have
Initialization/Finalization sections that contain code which will be run
when that executable or dll is run/terminated. This is basically what I
need here. Is there any equivallent to this in .NET/c#??? Basically I
need something that allows me to write some code which is guaranteed to
be run at program startup (and which isn't in static void Main() obviously).

Thanks in advance.

Best Regards,

James Crosswell
Microforge.net LLC
http://www.microforge.net
Dec 6 '06 #1
7 1786
"James Crosswell" <ja***@microforge.neta écrit dans le message de news:
%2******************@TK2MSFTNGP03.phx.gbl...

|I want to create a class with a static property as follows:
|
| class MyClass
| {
| private static List<MyHandlerRegisteredHandlers =
| new List<MyHandler>;
| }

| In Delphi/ObjectPascal (which I used to use) each code unit can have
| Initialization/Finalization sections that contain code which will be run
| when that executable or dll is run/terminated. This is basically what I
| need here. Is there any equivallent to this in .NET/c#??? Basically I
| need something that allows me to write some code which is guaranteed to
| be run at program startup (and which isn't in static void Main()
obviously).

Heheh ! welcome to the Delphi to C# conversion experience :-)

No, as far as I can discover, there is no implicit initialisation available
in C#; you really are going to have to, at least, call a static method or
property on each class that need registering; and that call would have to be
at the start of the static void Main() method..

May I suggest that, assuming that all the derived classes are in the same
assembly, that you use reflection to discover those classes that contain a
static "Register" method and call that method.

public static class HandlerRegister
{
...
public static void Initialise()
{
// get the classes from the assembly
// and if they contain a method "Register"
// call it
}
}

static void Main()
{
HandlerRegister.Initialise();

...
}

Joanna

--
Joanna Carter [TeamB]
Consultant Software Engineer
Dec 6 '06 #2

James Crosswell wrote:
I want to create a class with a static property as follows:

class MyClass
{
private static List<MyHandlerRegisteredHandlers =
new List<MyHandler>;
}

I then want to be able to create descendants of the MyHandler class
which will register themselves using a RegisterHandler method, which
basically adds one and only one instance of such classes to the static
list of RegisteredHandlers.

Each MyHandler will be able to deal a particular kind of object and will
have a bool HandlesObject(object aObject) method that returns true/false
to say wether it's capable of dealing with that object or not.

Finally, I want to be able to loop through an array of objects, check to
see if there is a MyHandler registered for each and, if so, call
MyHandler.DoSomething(theObject);

Initially I figured I could have each of the MyHandler descendant
classes implement a static constructor as follows:

class SomeObjectHandler : MyHandler
{
static SomeObjectHandler()
{
MyClass.RegisterHandler(new SomeObjectHandler());
}
}

However, it seems static constructors are only guaranteed to be called
sometime after the program starts and before an instance of the object
that they apply to is instantiated. In my case, the only instance of
SomeObjectHandler that will be instantiated is the one that gets
instantiated in it's own static constructor... which means that the
approach above isn't going to work.

In Delphi/ObjectPascal (which I used to use) each code unit can have
Initialization/Finalization sections that contain code which will be run
when that executable or dll is run/terminated. This is basically what I
need here. Is there any equivallent to this in .NET/c#??? Basically I
need something that allows me to write some code which is guaranteed to
be run at program startup (and which isn't in static void Main() obviously).
Funny, someone else posted a couple of days ago with a similar problem:

http://groups.google.com/group/micro...33faa227fcb77a

Joanna's suggestion is a good one. Here's another, lower-tech solution:
in each of your assemblies, write a sealed (or static in .NET 2.0)
class with a known name that has just one static method: Register().
Write explicit code into the Register class to register each applicable
class from the assembly.

When you load an assembly, look for that particular class by name, and
find its Register static method. If the class isn't there, or it has no
Register static method, then the assembly is malformed.

Joanna's solution is more automatic and adaptive to change, while mine
is low-tech and easy to understand. I'm sure that there are other ways,
as well.

Dec 6 '06 #3
Joanna Carter [TeamB] wrote:
No, as far as I can discover, there is no implicit initialisation available
in C#; you really are going to have to, at least, call a static method or
property on each class that need registering; and that call would have to be
at the start of the static void Main() method..

May I suggest that, assuming that all the derived classes are in the same
assembly, that you use reflection to discover those classes that contain a
static "Register" method and call that method.
Thanks Joanna,

And Bugger. One of the reasons I'm doing it in this round-about fashion
is that the app I'm designing is modular in nature and each module is in
a separate assembly. I'm trying to design some code which could do
generic stuff for all of the modules that are loaded.

One thing I'm thinking here is I have a namespace:

namespace MyApp.Server

And the modules are all in sub-namespaces like:

namespace MyApp.Server.AccountingModule
namespace MyApp.Server.OrdersModule
namespace MyApp.Server.InventoryModule

Is there any way to use reflection to get a list of classes within those
sub-namespaces? If I could do that then I think I could achieve what I want.

Best Regards,

James Crosswell
Microforge.net LLC
http://www.microforge.net
Dec 6 '06 #4
Bruce Wood wrote:
Joanna's suggestion is a good one. Here's another, lower-tech solution:
in each of your assemblies, write a sealed (or static in .NET 2.0)
class with a known name that has just one static method: Register().
Write explicit code into the Register class to register each applicable
class from the assembly.

When you load an assembly, look for that particular class by name, and
find its Register static method. If the class isn't there, or it has no
Register static method, then the assembly is malformed.
That sounds like a perfect solution - if the assembly doesn't implement
a MyCustomRegistration method then it's not one that's meant to be
loaded by my host app. Thanks.
Joanna's solution is more automatic and adaptive to change, while mine
is low-tech and easy to understand. I'm sure that there are other ways,
as well.
Thanks - I'll see if I can do it using reflection as well but if not
then the solution above will probably work.

Best Regards,

James Crosswell
Microforge.net LLC
http://www.microforge.net
Dec 6 '06 #5

James Crosswell wrote:
Joanna Carter [TeamB] wrote:
No, as far as I can discover, there is no implicit initialisation available
in C#; you really are going to have to, at least, call a static method or
property on each class that need registering; and that call would have to be
at the start of the static void Main() method..

May I suggest that, assuming that all the derived classes are in the same
assembly, that you use reflection to discover those classes that contain a
static "Register" method and call that method.

Thanks Joanna,

And Bugger. One of the reasons I'm doing it in this round-about fashion
is that the app I'm designing is modular in nature and each module is in
a separate assembly. I'm trying to design some code which could do
generic stuff for all of the modules that are loaded.

One thing I'm thinking here is I have a namespace:

namespace MyApp.Server

And the modules are all in sub-namespaces like:

namespace MyApp.Server.AccountingModule
namespace MyApp.Server.OrdersModule
namespace MyApp.Server.InventoryModule

Is there any way to use reflection to get a list of classes within those
sub-namespaces? If I could do that then I think I could achieve what I want.
I wouldn't worry about the namespaces. I haven't tried it, but the
thinking should go like this.

You just loaded the assembly, so you should be able to get your hands
on an Assembly object.
>From the Assembly object you can call GetExportedTypes() to get all
types (classes and structs) that the assembly exports for public
consumption.

Now you can just iterate over the array of Types and use Reflection to
see which ones have static Register methods that take no arguments (or
has a signature that you recognize). Any type that has a static
Register() method, you call it via Reflection's Invoke().

The upside to this technique is that you can add a new class to an
assembly, give it a static Register method, and it will be registered.
You don't have to remember to add it to a central Register method for
the whole assembly, so nothing is ever missed =lower maintenance.

The downside is that if you forget about this mechanism and add a
static Register() method to some class for some other reason, it will
be called when the assembly is loaded. Another downside is that all of
these Register methods are (or should be) public, which means that
they're now individually callable by client code. If you use a central
Register() method for the whole assembly, the individual Register()
methods for the classes can be internal and so hidden from outside
callers.

Dec 6 '06 #6
"Bruce Wood" <br*******@canada.coma écrit dans le message de news:
11*********************@j72g2000cwa.googlegroups.c om...

Thanks Bruce for your additional info, yet another way of skinning the same
cat :-)

Joanna

--
Joanna Carter [TeamB]
Consultant Software Engineer
Dec 6 '06 #7
Hi James,

Another solution might be to create a custom attribute that takes a single
type. You can check if the attribute is defined on the assembly, and if so
load the type. The type could implement an interface such as IStartupType
and you could call the method like that. This has several benefits over
reflection, but it requires the startup assemblies to reference some common
assemby in order to reference the interface and attribute.

// Define the attribute and interface in a shared assembly:

[AttributeUsage(AttributeTargets.Assembly, AllowMultiple=true)]
public class StartupTypeAttribute : Attribute
{
private Type type;
public Type Type { get { return type; } }

public StartupTypeAttribute(Type type)
{
this.type = type;
}

public IStartupType GetStartupType()
{
return (IStartupType) Activator.CreateInstance(type);
}
}

public interface IStartupType
{
void RunAtStartup();
}

// implement the interface in another assembly:

class SomeType : IStartupType
{
public void RunAtStartup() { ... }
}

// register SomeType in the same assembly:

[assembly: StartupType(typeof(SomeType))]

// in the main assembly you can load all of the startup types:

// assuming "assembly" is an instance of System.Reflection.Assembly instance
foreach (StartupTypeAttribute attribute in
assembly.GetCustomAttributes(typeof(StartupTypeAtt ribute), false))
{
attribute.GetStartupType().RunAtStartup();
}

This way it's somewhat type-safe, so at runtime you'll get real exception
info instead of TargetInvocationException if an error occurs in one of the
startup modules as happens when using reflection.

--
Dave Sexton

"James Crosswell" <ja***@microforge.netwrote in message
news:O8*************@TK2MSFTNGP02.phx.gbl...
Bruce Wood wrote:
>Joanna's suggestion is a good one. Here's another, lower-tech solution:
in each of your assemblies, write a sealed (or static in .NET 2.0)
class with a known name that has just one static method: Register().
Write explicit code into the Register class to register each applicable
class from the assembly.

When you load an assembly, look for that particular class by name, and
find its Register static method. If the class isn't there, or it has no
Register static method, then the assembly is malformed.

That sounds like a perfect solution - if the assembly doesn't implement a
MyCustomRegistration method then it's not one that's meant to be loaded by
my host app. Thanks.
>Joanna's solution is more automatic and adaptive to change, while mine
is low-tech and easy to understand. I'm sure that there are other ways,
as well.

Thanks - I'll see if I can do it using reflection as well but if not then
the solution above will probably work.

Best Regards,

James Crosswell
Microforge.net LLC
http://www.microforge.net

Dec 6 '06 #8

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

6
by: Dolphin White | last post by:
For example, I allocate some unmanaged resources in the static constructors, then how can I properly release the resource before the application exit? thx!
33
by: Chris Capel | last post by:
What is the rationale behind the decision not to allow abstract static class members? It doesn't seem like it's a logically contradictory concept, or that the implementation would be difficult or...
9
by: A J Le Couteur Bisson | last post by:
Could someone please confirm that static class constructors are only called at the first use of a non-static constructor on the class, or am I doing something wrong? If this is indeed the case...
7
by: Sunny | last post by:
Hi all, According C# Language Specification : 10.11 Static constructors: The static constructor for a class executes at most once in a given application domain. The execution of a static...
17
by: Picho | last post by:
Hi all, I popped up this question a while ago, and I thought it was worth checking again now... (maybe something has changed or something will change). I read this book about component...
4
by: hyd | last post by:
With C++/CLI - VS2005, is it possible to have static constructors that are automatically called when the owner assembly is loading ? Otherwise, how it is possible to call it without creating an...
12
by: Hemanth | last post by:
Hi, I have a base class with a static constructor and some abstract methods. Derived classes implement these methods. From articles on the web, it appears that there is no guarentee that this...
4
by: Morgan Cheng | last post by:
In C#, we can initialize static member variables in static constructor. Now, when to destruct these static member variables? If these variables hold external reference(e.g. log file stream), it is...
50
by: Juha Nieminen | last post by:
I asked a long time ago in this group how to make a smart pointer which works with incomplete types. I got this answer (only relevant parts included): ...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.