|
No, for Blackberry you will need to use Java
DaveIf this helped, please vote & accept answer!
Binging is like googling, it just feels dirtier. (Pete O'Hanlon)
BTW, in software, hope and pray is not a viable strategy. (Luc Pattyn)
|
|
|
|
|
I have a number of static instances of classes that do not get instantiated by the time I need them. These classes are loaded from external dll's, and may never be directly used. Here is an extremely simplified example.
A base class has a dictionary of all the instances of itself:
using System.Collections.Generic;
namespace Translators
{
public class Translator
{
static public Dictionary<string, Translator> allTranslators = new Dictionary<string, Translator>();
string language;
public Translator(string language)
{
allTranslators.Add(language, this);
}
}
}
A derived class in another assembly has specific implementation of the base class
namespace Translators
{
public class FrenchTranslator : Translator
{
private static FrenchTranslator TheFrenchTranslator = new FrenchTranslator();
private FrenchTranslator()
: base("French")
{
}
public static void Initialize() { }
}
}
Finally in a third assembly, a program, indirectly uses the derived class:
using Translators;
namespace ConsoleApplication4
{
class Program
{
static void Main(string[] args)
{
Translator myTranslator = Translators.Translator.allTranslators["French"];
}
}
}
In the case above if you break in a and look at myTranslator you will find it null. Because even though the assembly containing FrenchTranslator has been loaded, the class has not been used yet.
However if you change Main to the following it will be properly assigned.
static void Main(string[] args)
{
FrenchTranslator.Initialize();
Translator myTranslator = Translators.Translator.allTranslators["French"];
}
Now, I know that the static members don't get initialized until the class is utilized, my question is ... is there a way to utilize the class when the assembly gets loaded so that the static instances will be available.
Please note that the example above is only an example and not the actual problem. Consider that in the real case there are many thousands of instances of the base type that have been created in over a dozen assemblies. And that these instances could be indirectly used from many clients in many assemblies / applications. Also it is a requirement that the instances remain static instances.
Any help or thoughts would be appreciated.
The Thug
modified on Friday, April 16, 2010 8:39 AM
|
|
|
|
|
First thought:
Update the Dictionary in a static constructor.
Add static constructors to the derived classes.
OK, I'll have to make coffee first...
|
|
|
|
|
Can you change the class structure in the assemblies or are they 3rd party?
Dalek Dave: There are many words that some find offensive, Homosexuality, Alcoholism, Religion, Visual Basic, Manchester United, Butter.
Pete o'Hanlon: If it wasn't insulting tools, I'd say you were dumber than a bag of spanners.
|
|
|
|
|
The class structure can be changed but there are some limitations on what I can do and still have the solution be practical. What did you have in mind?
|
|
|
|
|
Well a few things occurred to me:
1. I'd have an ITranslator interface and have a dictionary of that. Minor point.
2. Having the Translator base class maintain a list of translators smacks of bad OO abstraction/separation of concerns, a translator translates for a language, it doesn't keep a list translators. I also think it makes the symantics of accessing a translator a little wierd. You might have a good reasons for doing this, however.
3. Following on from 2, I'd have a Singleton (or possibly static) object responsible for maintaining a the Dictionary of translators. You can lazily load the dictionaries, and/or initialise some at startup. The will also help to separate the concerns and will make the loading code clearer as it isn't in with the translation stuff.
I often find that when I struggle with problems like this, it is because there is an underlying flaw in my OO design. Hope this helps!
Dalek Dave: There are many words that some find offensive, Homosexuality, Alcoholism, Religion, Visual Basic, Manchester United, Butter.
Pete o'Hanlon: If it wasn't insulting tools, I'd say you were dumber than a bag of spanners.
|
|
|
|
|
Yeah, there's that, but there are bigger obstacles to overcome first.
|
|
|
|
|
I have to say I disagree. First it's a good idea to sanity check what is going on.
Secondly, get the model right and you don't spend all your time p*ssing into the wind.
Thirdly, this looks like a strategy pattern might be a good fit.
Fourthly, something needs to initialise the translators some where. This can't happen internally to the class as descirbed, and would lie more naturally in a class managing the translator dictionary.
Dalek Dave: There are many words that some find offensive, Homosexuality, Alcoholism, Religion, Visual Basic, Manchester United, Butter.
Pete o'Hanlon: If it wasn't insulting tools, I'd say you were dumber than a bag of spanners.
|
|
|
|
|
Keith Barrow wrote: something needs to initialise the translators
Yes, that's the hard part, and until you know how to do it it doesn't matter where you put the code that you haven't even written yet.
I totally agree with having a separate manager class that isn't hard-coded to any particular client class. The one I just wrote is generic.
|
|
|
|
|
Will you only instantiate each class once? Some form of Singleton may be beneficial here.
Second mug of coffee coming up...
|
|
|
|
|
Nope. Each of the derived classes will have multiple static members, each of which are instances of the derived class, being added to the dictionary in the base class.
|
|
|
|
|
Hmmm... well, that doesn't really make it any more difficult...
|
|
|
|
|
Hi,
Someone has to take the initiative for a collection to be populated.
if you don't plan on touching the specialized translators before calling on AllTranslators, the only solution I can see is by having reflection code in the static initializer of Translator, so it can go out and search for translators, feeding them to AllTranslators.
[EDIT]
You should not make allTranslators public, instead have a public AllTranslators property; you then can postpone the reflective search till the property is used for the first time.
[/EDIT]
|
|
|
|
|
Luc Pattyn wrote: Someone has to take the initiative for a collection to be populated
Therein lies the rub. .net likes to be lazy in its instantiation, and even allows the developer to make it even lazier.
What we need here is to make .net be pro-active.
Luc Pattyn wrote: reflection code in the static initializer of Translator
I don't even think that would do it.
It appears that, in theory, this should even work for plug-in assemblies that get loaded after the manager class.
I certainly haven't found a way to tell the runtime to initialize the class immediately upon load rather than waiting for some code to reference it.
|
|
|
|
|
PIEBALDconsult wrote: I certainly haven't found a way to tell the runtime to initialize the class immediately upon load
there isn't AFAIK. And I never felt a need for it either. The OP seems like a request for a regular plug-in scheme.
|
|
|
|
|
Luc Pattyn wrote: a regular plug-in scheme
Seems very similar, yes. But something will have to register the plug-in before the client can request it.
|
|
|
|
|
So I tried that approach out, with a method that I called on first access of the dictionary,
static private void initialize()
{
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
foreach (var type in assembly.GetTypes())
{
if (type.IsSubclassOf(typeof(Translator)))
{
type.InvokeMember("Initialize", BindingFlags.InvokeMethod, null, null, null);
}
}
}
}
It is pretty heavy handed, but it has one big benefit, over say tying into the assembly AssemblyLoad event, there is nothing extra for the Translator client to do. It also still has a problem, the derived class assembly still has to be loaded at some point. But I see no way around that.
FYI, I also tried a assembly attribute similar to the one http://joshsmithonwpf.wordpress.com/2010/04/07/assembly-level-initialization-at-design-time/ but alas the attribute is only called if reflection is used on the assembly
So right now this is the best solution I have.
Thanks,
|
|
|
|
|
thugthug wrote: the assembly still has to be loaded at some point
Two common approaches are:
1. provide a GUI Control (Menu, ComboBox) listing all assemblies from a specific directory, and allow the user to choose which one(s) to load.
2. load all assemblies from a specific directory.
And there is a middle way: if all you need is a specific translator, you might have a class and method Translators.LoadOne(string name) that first checks if it has been loaded before, and if not, goes to the specific directory, does a filename search, and loads the matching assembly.
|
|
|
|
|
That's more-or-less what I have working at the moment -- except with a generic manager class using parameter-less constructors.
You could probably add a method to the manager that will load specified assemblies:
manager.Load ( "plugins\\*.dll" ) ;
I also defined an interface and am using type.IsAssignableFrom rather than type.IsSubclassOf .
|
|
|
|
|
One last change that I threw in was to combine a couple efforts,
1) Using reflection.
2) Using assembly attributes.
First add a custom attribute to the assembly info for FrenchTranslator that looks like this:
[assembly: Bootstrapper()]
[AttributeUsage(AttributeTargets.Assembly)]
class BootstrapperAttribute : Attribute
{
public BootstrapperAttribute()
{
Translators.FrenchTranslator.Initialize();
}
}
So if this attribute ever did load, it would call the the method Translators.FrenchTranslator.Initialize(), and the static instance would come into being. Problem is no one is every going to look for this attribute and it will not ever be loaded!
To get the attribute loaded, I added an initialize method in the translator class looks that looks like this and is called on first access to the dictionary.
static private void initialize()
{
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
assembly.GetCustomAttributes(true);
}
}
So someone accesses the dictionary for the first time, the initialize method causes the all the assemblies with the specified attribute to tell there contained classes to initialize, and poof the static members exist.
The benefit of this over the previous method is that now I don't have to check every single type that has been loaded in.
Much Thanks to all.
James
|
|
|
|
|
Veddy intewesting...
Though it still only knows about types in assemblies that have been loaded.
I've been looking at the plug-in angle of this and have it working to some extent.
It still requires a parameter-less constructor, rather than an Initialize method.
I am considering using attributes to tell the manager how to instantiate the class.
I suggest you take Keith's advice and separate the translator classes from the manager class.
|
|
|
|
|
Considering:
0) We have pretty much determined that what you were originally asking about is currently impossible.
1) You need to enumerate the types in the loaded assemblies (and/or develop an all-out plug-in system).
I question whether or not the static instances and Initialize methods are required at this point -- I think that they were simply failed attempts at trying to get it work the way you thought it might.
Certainly, the way I'm doing it doesn't use either.
Aren't your static instances merely duplicates of what's in the Dictionary?
And is there any code in the Initialize methods?
Can you remove them without harming the process? (Perhaps alter your Attribute to refer to something else?)
(I'm also not so thrilled about the Attribute.)
|
|
|
|
|
PIEBALDconsult wrote: Aren't your static instances merely duplicates of what's in the Dictionary?
Undoubtedly.
PIEBALDconsult wrote: And is there any code in the Initialize methods?
Nope.
Can you remove them without harming the process? (Perhaps alter your Attribute to refer to something else?)
(I'm also not so thrilled about the Attribute.)
Afraid not.
To be more clear:
Actually the static instances are the primary method of accessing the data in most (99%) cases , this look-up-by-name feature is only needed for a small sub-set of clients. The problem being that when the clients do look-up-by-name there was no guarantee that the class had ever been accessed, and the static instances initialized. The dictionary serves two roles, first as the look-up-by-name feature and second maintaining uniqueness in the names (this is very important in the actually application).
|
|
|
|
|
If you're not usually looking them up by name, then why require that the names be unique?
I recommend having the lookup as the normal/only access method.
But I suppose it may be too late.
|
|
|
|
|
Hi there,
I'm currently trying to serialize a wsdl.exe generated object
[System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "2.0.50727.1432")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://myNamespace/")]
public partial class marketDataEventV1 {
using the following lines of code:
marketDataEventV1 mdEvent = CreateMarketDataEventV1();
XmlSerializer ser = new XmlSerializer(typeof(marketDataEventV1));
StringBuilder sb = new StringBuilder();
ser.Serialize(new StringWriter(sb), mdEvent);
Now, having a look to sb.ToString() shows, that the result (string) does not contain the namespace declaration.
I wonder now, how to get the serializer taking account for the namespace?!
Thanks in advance!
|
|
|
|
|