Here is a code sample
[Guid("159463FB-A87A-4BBB-BCA1-064CD84495FB")]
public interface ISettingsFactory
{
ISettings GetSettings(string userName);
}
[Guid("FD11B979-0ED1-41fb-8EB0-1234512345D0")]
public interface ISettings
{
string PrivateKey {get;}
}
[Guid("782937826-705F-4be2-1234-A748332D6D1")]
[ClassInterface(ClassInterfaceType.None)]
public class SettingsFactory : ISettingsFactory
{
public ISettings GetSettings(string userName)
{
return new Settings(userName);
}
}
[Guid("8BDC1F18-48FD-4a49-8DF3-D81C6321657B")]
[ClassInterface(ClassInterfaceType.None)]
public class Settings : ISettings
{
private readonly PrivateData privateData;
public Settings(string userName)
{
privateData= PrivateData.Load(userName);
}
public string PrivateKey
{
get { return privateData.Key; }
}
}
The problem is when creating SettingsFactory COM class from VB6 code and calling method GetSettings(userName)
settings = factory.GetSettings(userName);
key = settings.PrivateKey //<--- Exception occurs saying "Read write from protected memory is not allowed" or something like this.
The problem disappears when in GetSettings method I save Settings instance in field of SettingsFactory, so that GC doesn't collect it. Does anyone know why is this happening? I mean why GC collects objects that are exposed to COM? Isn't RCW increases the ref number on the Settings object after GetSettings get called?
I think the problems is that privateData.Key is not being marshalled correctly. I can't see the definition for the type of Key but my guess is it is a ptr to some kind of data and tha this data isn't being marshalled correctly. If thats the case you probably need to use one of the Marhal.PtrToXXX fumctions.
A great place to start if you want to learn more about using COM objects from .net are the MSDN articles on Runtime Callable Wrappers
Related
This is an architecture problem. Programmers encounter this encapsulation problem quite often, but I haven't yet seen a complete and clean solution.
Related questions:
readonly class design when a non-readonly class is already in place
Controlling read/write access to fields
Normally, in OOP paradigm, objects store their data in fields. The class' own methods have full access to its fields. When you need to return value, you just return a copy of the data, so that the outside code cannot break the data.
Now suppose that the data pieces are complex, so they're themselves encapsulated in class objects and that these objects cannot be easily copied. Now, if you return such object from some property, the outside code has the same access to it as your internal code. For example, if you return a List<int>, everyone can add values to it. This is usually undesirable.
This problem is usually worked around using read-only wrappers - you wrap your full-access internal objects in read-only wrappers before returning. The problem with this approach is that the wrapper may be a poor substitution for the wrapped value - the wrapper is a different class. (And if you derive the read-only wrapper from the modifiable class (or vise-versa), then anybody can up-cast/down-cast the "read-only" object to the modifiable object, breaking the protection.)
I want a pattern such that:
The data (say, an int value) has "public/read-only API" and "private/modifiable API".
Only the object creator has access to the "private/modifiable API".
The private/public APIs may have both passive parts (e.g. methods, properties) and active parts (e.g. events).
Delegates should not be used except at the object creation stage. All calls should be direct.
The access to the internal data from the "public/read-only API" (and, preferably, from the "private/modifiable API" too) should be as direct as possible. I don't want a big stack of wrappers to accumulate when composing such objects.
Here are the sample interfaces:
interface IPublicApi {
int GetValue();
}
interface IPrivateApi {
void SetValue(int value);
}
interface IPrivateConsumer {
void OnValueChanged(); //Callback
}
I have devised such scheme. I want you to critique my solution or give your own solution.
There are several sub-problems that have to be solved.
How to allow the "private API" code to access the private data without allowing the outside code to call it?
How to give the "private API" access to the object creator?
How to establish the two-way communication between the object and the code using the private API (calling/getting called)?
My system consists of these classes:
ReadableInt is the public API
ReadableInt.PrivateApi is the raw private API proxy object
ReadableInt.IPrivateConsumer is the public-to-private callback interface
public sealed class ReadableInt {
int _value;
IPrivateConsumer _privateConsumer;
public ReadableInt(IPrivateConsumer privateConsumer, Action<PrivateApi> privateConsumerInitializer) {
_privateConsumer = privateConsumer;
var proxy = new PrivateApi(this);
privateConsumerInitializer(proxy);
}
public int GetValue() {
return _value;
}
private void SetValue(int value) {
_value = value;
_privateConsumer.OnValueChanged();
}
public interface IPrivateConsumer {
void OnValueChanged();
}
public class PrivateApi {
ReadableInt _readableInt;
internal PrivateApi(ReadableInt publicApi) {
_readableInt = publicApi;
}
public void SetValue(int value) {
_readableInt.SetValue(value);
}
}
}
WritableInt is some private API consumer, which may reside in another assembly.
public sealed class WritableInt : ReadableInt.IPrivateConsumer {
ReadableInt _readableInt;
ReadableInt.PrivateApi _privateApi;
public WritableInt() {
_readableInt = new ReadableInt(this, Initialize);
}
void Initialize(ReadableInt.PrivateApi privateApi) {
_privateApi = privateApi;
}
public ReadableInt ReadOnlyInt { get { return _readableInt; } }
public void SetValue(int value) {
_privateApi.SetValue(value);
}
void ReadableInt.IPrivateConsumer.OnValueChanged() {
Console.WriteLine("Value changed!");
}
}
One can use the classes like this:
var writeableInt = new WritableInt();
var readableInt = writeableInt.ReadOnlyInt;
This is how the system works:
The private API (ReadableInt.PrivateApi) gains access to the main object (ReadableInt) private members by being an inner class. No up-casting/down-casting security breaches.
Notice that the ReadableInt.PrivateApi constructor is marked internal, so only ReadableInt can create the instances. I could not find a more elegant way to prevent anyone from creating a ReadableInt.PrivateApi from a ReadableInt object.
In general, ReadableInt needs a reference to the private API consumer to call it (notifications etc.). To decouple the public API from concrete private API consumers, the private API consumer is abstracted as the ReadableInt.IPrivateConsumer interface. ReadableInt receives the reference to a ReadableInt.IPrivateConsumer object through the constructor.
The private API controller object (ReadableInt.PrivateApi) is given to the creator (WriteableInt) via callback (Action<PrivateApi>) passed to the ReadableInt constructor. It's extremely ugly. Can anyone propose another way?
There is a small problem: WritableInt.OnValueChanged() method is private, but is effectively public as it's an interface method. This can be solved with a delegate or a proxy. Is there any other way?
This system works, but has some parts that I'm not proud of. I particularly dislike the initialization stage when all parts are linked together. Can this be simplified somehow?
How I do it
The question is quite interesting. I'm not in any way an expert in OOP (God! I wish I would!), but here is how I do it:
public interface IReadOnlyFoo
{
int SomeValue
{
get;
}
}
public class Foo: IReadOnlyFoo
{
public int SomeValue
{
get;
set;
}
}
public class Bar
{
private Foo foo;
public IReadOnlyFoo Foo
{
get
{
return foo;
}
}
}
It's not very secure, since you can cast IReadOnlyFoo to Foo. But my philosophy here is the following: when you cast, you take all the responsibility on yourself. So, if you shoot yourself in the foot, it's your fault.
How I would do if I were to avoid casting problem
First thing to consider here is that there are value types and reference types.
Value types
For the sake of this answer I would classify value types for pure data types (int, float, bool, etc.) and structures.
Pure data types
It is interesting that you explain your problem using int which is value type. Value types are get copied by assignment. So, you don't need any kind of wrapper or read only reference mechanics for int. This is for sure. Just make a read-only property or property with private/protected setter and that's it. End of story.
Structures
Basically, the same thing. In good designed code, you don't need any wrappers for structs. If you have some reference type values inside struct: I would say that this is a poor design.
Reference types
For reference types your proposed solution looks too complicated. I would do something like this:
public class ReadOnlyFoo
{
private readonly Foo foo;
public ReadOnlyFoo(Foo foo)
{
this.foo = foo;
}
public SomeReferenceType SomeValue
{
get
{
return foo.SomeValue;
}
}
}
public class Foo
{
public int SomeValue
{
get;
set;
}
}
public class Bar
{
private Foo foo;
public readonly ReadOnlyFoo Foo;
public Bar()
{
foo = blablabla;
Foo = new ReadOnlyFoo(foo);
}
}
C#. I have a base class called FileProcessor:
class FileProcessor {
public Path {get {return m_sPath;}}
public FileProcessor(string path)
{
m_sPath = path;
}
public virtual Process() {}
protected string m_sath;
}
Now I'd like to create to other classes ExcelProcessor & PDFProcessor:
class Excelprocessor: FileProcessor
{
public void ProcessFile()
{
//do different stuff from PDFProcessor
}
}
Same for PDFProcessor, a file is Excel if Path ends with ".xlsx" and pdf if it ends with ".pdf". I could have a ProcessingManager class:
class ProcessingManager
{
public void AddProcessJob(string path)
{
m_list.Add(Path;)
}
public ProcessingManager()
{
m_list = new BlockingQueue();
m_thread = new Thread(ThreadFunc);
m_thread.Start(this);
}
public static void ThreadFunc(var param) //this is a thread func
{
ProcessingManager _this = (ProcessingManager )var;
while(some_condition) {
string fPath= _this.m_list.Dequeue();
if(fPath.EndsWith(".pdf")) {
new PDFProcessor().Process();
}
if(fPath.EndsWith(".xlsx")) {
new ExcelProcessor().Process();
}
}
}
protected BlockingQueue m_list;
protected Thread m_thread;
}
I am trying to make this as modular as possible, let's suppose for example that I would like to add a ".doc" processing, I'd have to do a check inside the manager and implement another DOCProcessor.
How could I do this without the modification of ProcessingManager? and I really don't know if my manager is ok enough, please tell me all your suggestions on this.
I'm not really aware of your problem but I'll try to give it a shot.
You could be using the Factory pattern.
class FileProcessorFactory {
public FileProcessor getFileProcessor(string extension){
switch (extension){
case ".pdf":
return new PdfFileProcessor();
case ".xls":
return new ExcelFileProcessor();
}
}
}
class IFileProcessor{
public Object processFile(Stream inputFile);
}
class PdfFileProcessor : IFileProcessor {
public Object processFile(Stream inputFile){
// do things with your inputFile
}
}
class ExcelFileProcessor : IFileProcessor {
public Object processFile(Stream inputFile){
// do things with your inputFile
}
}
This should make sure you are using the FileProcessorFactory to get the correct processor, and the IFileProcessor will make sure you're not implementing different things for each processor.
and implement another DOCProcessor
Just add a new case to the FileProcessorFactory, and a new class which implements the interface IFileProcessor called DocFileProcessor.
You could decorate your processors with custom attributes like this:
[FileProcessorExtension(".doc")]
public class DocProcessor()
{
}
Then your processing manager could find the processor whose FileProcessorExtension property matches your extension, and instantiate it reflexively.
I agree with Highmastdon, his factory is a good solution. The core idea is not to have any FileProcessor implementation reference in your ProcessingManager anymore, only a reference to IFileProcessor interface, thus ProcessingManager does not know which type of file it deals with, it just knows it is an IFileProcessor which implements processFile(Stream inputFile).
In the long run, you'll just have to write new FileProcessor implementations, and voila. ProcessingManager does not change over time.
Use one more method called CanHandle for example:
abstract class FileProcessor
{
public FileProcessor()
{
}
public abstract Process(string path);
public abstract bool CanHandle(string path);
}
With excel file, you can implement CanHandle as below:
class Excelprocessor: FileProcessor
{
public override void Process(string path)
{
}
public override bool CanHandle(string path)
{
return path.EndsWith(".xlsx");
}
}
In ProcessingManager, you need a list of processor which you can add in runtime by method RegisterProcessor:
class ProcessingManager
{
private List<FileProcessor> _processors;
public void RegisterProcessor(FileProcessor processor)
{
_processors.Add(processor)
}
....
So LINQ can be used in here to find appropriate processor:
while(some_condition)
{
string fPath= _this.m_list.Dequeue();
var proccessor = _processors.SingleOrDefault(p => p.CanHandle(fPath));
if (proccessor != null)
proccessor.Process(proccessor);
}
If you want to add more processor, just define and add it into ProcessingManager by using
RegisterProcessor method. You also don't change any code from other classes even FileProcessorFactory like #Highmastdon's answer.
You could use the Factory pattern (a good choice)
In Factory pattern there is the possibility not to change the existing code (Follow SOLID Principle).
In future if a new Doc file support is to be added, you could use the concept of Dictionaries. (instead of modifying the switch statement)
//Some Abstract Code to get you started (Its 2 am... not a good time to give a working code)
1. Define a new dictionary with {FileType, IFileProcessor)
2. Add to the dictionary the available classes.
3. Tomorrow if you come across a new requirement simply do this.
Dictionary.Add(FileType.Docx, new DocFileProcessor());
4. Tryparse an enum for a userinput value.
5. Get the enum instance and then get that object that does your work!
Otherwise an option: It is better to go with MEF (Managed Extensibility Framework!)
That way, you dynamically discover the classes.
For example if the support for .doc needs to be implemented you could use something like below:
Export[typeof(IFileProcessor)]
class DocFileProcessor : IFileProcessor
{
DocFileProcessor(FileType type);
/// Implement the functionality if Document type is .docx in processFile() here
}
Advantages of this method:
Your DocFileProcessor class is identified automatically since it implements IFileProcessor
Application is always Extensible. (You do an importOnce of all parts, get the matching parts and Execute.. Its that simple!)
Needs -
To declare shared exports of the same interface. The exports are marked by unique export names so consumers may import a particular flavor of the export.
To inject a common instance of the class into a set of objects but to not share a common instance across sets of objects [This makes me use shared exports using different keys - one set of objects can use a single key to get satisfy their shared import need]
Here is the export class
public interface IMyExport
{
void Display();
}
public class MyExport : IMyExport
{
private Guid _id = Guid.NewGuid();
public void Display()
{
Console.WriteLine("Instance ID = "+_id);
}
}
and here is how I export instances of the class
public static class ExportInitialization
{
[Export("Type A", typeof(IMyExport)),
Export("Type B", typeof(IMyExport))]
public static IMyExport IceCreamExport
{
get
{
return new MyExport();
}
}
}
Consumers may import specific instances in the following manner
[Export]
public class ImporterA
{
private readonly IMyExport _myExport;
[ImportingConstructor]
public ImporterA([Import("Type A")]IMyExport myExport)
{
_myExport = myExport;
}
public void Display()
{
_myExport.Display();
}
}
[Export]
public class ImporterB
{
private readonly IMyExport _myExport;
[ImportingConstructor]
public ImporterB([Import("Type B")]IMyExport myExport)
{
_myExport = myExport;
}
public void Display()
{
_myExport.Display();
}
}
class Program
{
[Import]
public ImporterA ImporterA { get; set; }
[Import]
public ImporterB ImporterB { get; set; }
static void Main(string[] args)
{
new Program().Run();
}
public void Run()
{
var container = new CompositionContainer(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
container.ComposeParts(this);
ImporterA.Display();
ImporterB.Display();
Console.ReadKey();
}
}
This used to work fine with .Net 4.0 but when .Net 4.5 is installed - I get the following ouptut
Instance ID = 78bba41a-0c48-44fc-ae69-f0ead96371f9
Instance ID = 78bba41a-0c48-44fc-ae69-f0ead96371f9
Notice that the same instance of the object is returned for both imports. Am I breaking some undocumented rule regarding exporting via static properties?
I found that exporting the specific instances from two distinct static properties ensures that 2 distinct instances are returned.
[Export("Type A", typeof(IMyExport))]
public static IMyExport ExportA
{
get
{
return new MyExport();
}
}
[Export("Type B", typeof(IMyExport))]
public static IMyExport ExportB
{
get
{
return new MyExport();
}
}
This is puzzling since in the unmodified version the static getter was creating a new instance on every get. Not sure if this is the result of some C#/.Net optimization introduced with 4.5 or if this is a MEF issue
This is related to the MEF parts lifetime.
The default for MEF attributes is that components do not say whether they care to get a new instance each time or not.
Meaning that:
Your ExportAttribute does not specify whether exported instances can or should be shared;
Both of the ImportAttributes do not specify whether their import should be shared or not;
The default behavior of MEF is that, if it is not forbidden from sharing instances, it will. Meaning that, according to the documentation, the behavior of .NET 4.5 is the correct one: the instance of MyExport is shared, given that no-one on either side explicitly forbade sharing.
I think that .NET 4.0 had a bug/discrepancy where the static property was called every time, which resulted in what you observed, that is, non shared instances. And you were relying on that bug. I think that the bug finds its origin in a fundamental, framework-wide expectation for properties - it is very unusual to have a static property create a new, semantically distinct, instance for each property call.
I believe you should:
Replace your static property export with a static method export;
Specify the creation policy to non-shared, on either the Export side or the Import side;
Lets say I have an abstract object which can be implemented by multiple, separate plugin authors. (For instance, a bug database connection) I don't want consumers of my bits to have to deal with each specific plugin type.
I also want to separate the process of parsing a configuration file from the process of actually initializing database plugins and other such things.
To that end, I came up with something like this:
public interface IConfiguration
{
// No members
}
public interface IConnection
{
// Members go in here
void Create();
void Update();
void Delete();
}
public interface IConnectionProvider
{
// Try to interpret file as a configuration, otherwise return null
IConfiguration ParseConfiguration(Stream configurationContents);
IConnection Connect(IConfiguration settings);
}
public class ThingyRepository
{
// Lets say there is a constructor that initializes this with something
List<IConnectionProvider> providers;
// Insulates people from the actual connection provider
KeyValuePair<IConfiguration, IConnectionProvider> Parse(string filename)
{
IConnection result = null;
IConnectionProvider resultProvider = null;
foreach (var provider in this.providers)
{
using (Stream fs = OpenTheFileReadonly(filename))
{
IConnection curResult = provider.ParseConfiguration(fs);
if (curResult == null)
{
continue;
}
else
{
if (result == null)
{
result = curResult;
resultProvider = provider;
}
else
{
throw new Exception ("ambguity!");
}
}
}
}
if (result == null)
{
throw new Exception ("can't parse!");
}
return new KeyValuePair<IConfiguration, IConnectionProvider>(
result, resultProvider);
}
}
My question is, I've got this empty interface which is supposed to serve as an opaque handle to whatever settings were loaded from the indicated file. The specific implementer of IConnectionProvider knows what bits it needs in its configuration that it would load from a file, but users of this library should be insulated from that information.
But having an empty interface seems strange to me. Does this sort of thing make sense or have I done something horribly wrong?
The basic concept of an interface with no members, that simply identifies implementors as being something instead of the interface's normal job of identifying what an object has or does, is known as a "flag interface". It has its uses, but use them sparingly. I, for instance, typically use them in a hierarchical format to identify domain objects that should be persisted to a particular data store:
//no direct implementors; unfortunately an "abstract interface" is kind of redundant
//and there's no way to tell the compiler that a class inheriting from this base
//interface is wrong,
public interface IDomainObject
{
int Id {get;}
}
public interface IDatabaseDomainObject:IDomainObject { }
public interface ICloudDomainObject:IDomainObject { }
public class SomeDatabaseEntity:IDatabaseDomainObject
{
public int Id{get;set;}
... //more properties/logic
}
public class SomeCloudEntity:ICloudDomainObject
{
public int Id{get;set;}
... //more properties/logic
}
The derived interfaces tell me nothing new about the structure of an implementing object, except that the object belongs to that specific sub-domain, allowing me to further control what can be passed where:
//I can set up a basic Repository pattern handling any IDomainObject...
//(no direct concrete implementors, though I happen to have an abstract)
public interface IRepository<T> where T:IDomainObject
{
public TDom Retrieve<TDom>(int id) where TDom:T;
}
//... Then create an interface specific to a sub-domain for implementations of
//a Repository for that specific persistence mechanism...
public interface IDatabaseRepository:IRepository<IDatabaseDomainObject>
{
//... which will only accept objects of the sub-domain.
public TDom Retrieve<TDom>(int id) where TDom:IDatabaseDomainObject;
}
The resulting implementations and their usages can be checked at compile-time to prove that an ICloudDomainObject isn't being passed to an IDatabaseRepository, and at no time can a String or byte[] be passed into the repository for storage. This compile-time security isn't possible with attributes or properties, which are the other primary ways to "flag" a class as having some special significance.
So in short, it's not bad practice per se, but definitely ask yourself what you want out of the flag interface, and ask yourself if any state or logical data that would commonly be implemented on an IConfiguration (perhaps the name or other identifier of said configuration, or methods to load or persist it to the chosen data store) could do with some enforced standardization.
I think this is entirely valid. I'm designing an API where the caller has to first get an opaque "session" object and then pass it in to subsequent calls.
Different implementations of the API will use totally different implementations of the session object, so the session object clearly isn't an abstract class with different subclasses; it's an interface. Since the session object has no behavior visible to the caller, it seems to me the only logical model for this is an interface with no members.
I've seen this problem come up a lot, but never adequately handled, and I haven't seen it on Stack Overflow, so here goes. I wish there were a way to put this shortly and succinctly without lacking clarity, but I can't seem to shorten it, so bear with me...
A good case-study (my current case, of course) to illustrate the problem follows:
I write code for many locations, a Parent Compary (parentco), and several satellite locations (centers). I have two 'Managers', one designed for the parentco, and one designed for the centers (deployed many times). I also have two libraries, one for the centers, and one generic library (that is used at the centers and the parentco), that programs can include to communicate to the appropriate Manager (via TCP). The library for the centers has several classes designed to wrap database tables and other 'Messages' to do other things, and the generic library has a few 'Messages,' too, such as 'end connection,' 'invoke a process,' and others.
The Question:
When the Manager recieves a Message that is defined in the 'generic' library, how can it know which type of message it is? The first-blush solution would be something like this:
namespace generic_library
{
public interface IMessage_Creator
{
public IMessage Create_Message(short id);
}
public interface IMessage
{
short Message_ID { get; }
}
/// <summary>Perhaps a message to kill the current connection</summary>
public class Generic_Message1 : IMessage
{
public short Message_ID { get { return ID; } }
internal const short ID = 1;
}
public static class Message_Handler
{
private static readonly System.Collections.Generic.List<IMessage_Creator> _creators =
new System.Collections.Generic.List<IMessage_Creator>();
public static void Add_Creator(IMessage_Creator creator)
{
_creators.Add(creator);
}
public static IMessage Get_Message(short id)
{
switch (id)
{//the Generic library knows about the generic messages...
case Generic_Message1.ID:
return new Generic_Message1();
}
//no generic message found, search the registered creators.
IMessage ret = null;
foreach (IMessage_Creator creator in _creators)
{
ret = creator.Create_Message(id);
if (ret != null)
{
return ret;
}
}
//null if no creator was found.
return ret;
}
}
}
namespace center
{
public class Center_Creator : generic_library.IMessage_Creator
{
static Center_Creator()
{
generic_library.Message_Handler.Add_Creator(new Center_Creator());
}
public generic_library.IMessage Create_Message(short id)
{
switch (id)
{//The center library knows about center-specific messages
case center_message1.ID:
return new center_message1();
}
//we return null to say, "I don't know about that message id."
return null;
}
}
public class center_message1 : generic_library.IMessage
{
public short Message_ID
{
get { return ID; }
}
internal const short ID = 2;
}
}
A little explanation. As you can see, the center and generic library have their own messages they can handle. The center interface (here represented by namespace center) registers his creator, Center_Creator, in the static constructor so when the Message_Handler gets a message of his type, the creator will be called on to generate the correct message.
The problem with this approach:
You may have already seen the problem here, and that is:
If the class Center_Creator is never accessed at all (one is never created, and a static method is never invoked) by code, which should be the case until a message of that type is recieved, the static constructor, static Center_Creator() is never invoked, so the Message_Handler never knows about this creator.
That's all fine and dandy, but I don't know how to fix it. Many people have suggested using reflection to invoke the Center_Creator Type Initializer, but I don't want to put that burden on every program that uses this library!
What is the Stack Overflow community's suggestion? Please let me know if I can simplify this to help make it more accessible for the community.
EDIT:
The code is for the generic library and the Center Library. As you can see, I will have the same issues with the Parent Company library.
A diagram of the architecture. http://cid-0676bb3c1f8d6777.office.live.com/self.aspx/Public/Manager.jpg
Image.
Let's break this down:
You have an application which is to send & receive certain types of messages.
A message type must be registered before it can be read, however,
You do not register the type until you send a message, but
You want to be able to read a message before you write one.
Clearly the answer is that you are registering your message types at the wrong time.
I would suggest an explicitly called Init() method for message types. This could be done by using reflection to scan the libraries to see would types are defined, or by manually listing them.
your message handlers can be seen as plugins which makes your problem a potential fit for the Managed Extensibility Framework. Since .Net 4 it's also shipped with the .Net framework.
You can find sample introductions to MEF here and here.
I've put together a litte example to show that it's quite simple to use basic MEF functionality (although there is much more you can do with it). First there is a PluginHost class which will host the plugins in its Plugins collection. Then there's a simple interface containing just the property Description and an example implementation of a plugin called ExamplePlugin.
The Plugins collection will be filled by the container.ComposeParts(..) method called in the constructor. All that's required to make that magic happen are the [Export] and [ImportMany] attributes.
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
namespace Playground
{
public class Program
{
static void Main(string[] args)
{
PluginHost host = new PluginHost();
host.PrintListOfPlugins();
Console.ReadKey();
}
}
public class PluginHost
{
[ImportMany]
public IEnumerable<IPlugin> Plugins { get; set; }
public PluginHost()
{
var catalog = new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly());
var container = new CompositionContainer(catalog);
container.ComposeParts(this);
}
public void PrintListOfPlugins()
{
foreach (IPlugin plugin in Plugins)
Console.WriteLine(plugin.Description);
}
}
public interface IPlugin
{
string Description { get; }
}
[Export(typeof(IPlugin))]
public class ExamplePlugin : IPlugin
{
#region IPlugin Members
public string Description
{
get { return "I'm an example plugin!"; }
}
#endregion
}
}
UPDATE: You can use so called Catalogs to discover plugins in more than one assembly. For example there is a DirectoryCatalog which gives you all exports found in all assemblies in a given directory.
AppDomain.CurrentDomain.GetAssemblies(); returns an array of all assemblies loaded into the current AppDomain. You could then iterate over that array to create an AggregateCatalog containing an AssemblyCatalog per loaded assembly.
Some ideas:
Use .NET serialization to serialize/deserialize your messages and put them in a class library used by both ends (or even use WCF to handle communication).
Add a custom attribute to your creator classes and populate the creator list using reflection at the first time Get_Message is called ("if (!initialized) FindAndAddCreators();").
Introduce some initialization method in your library that registers all the creator classes.
Try using a factory pattern.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
namespace SO
{
class Program
{
static void Main(string[] args)
{
MessageFactory factory = new MessageFactory();
IMessage msg = factory.CreateObject(1);
IMessage msg2 = factory.CreateObject(2);
}
}
public interface IMessage
{
short Message_ID { get; }
}
public class Generic_Message1 : IMessage
{
public short Message_ID { get { return ID; } }
internal const short ID = 1;
}
public class center_message1 : IMessage
{
public short Message_ID { get { return ID; } }
internal const short ID = 2;
}
public class MessageFactory
{
private Dictionary<short, Type> messageMap = new Dictionary<short, Type>();
public MessageFactory()
{
Type[] messageTypes = Assembly.GetAssembly(typeof(IMessage)).GetTypes();
foreach (Type messageType in messageTypes)
{
if (!typeof(IMessage).IsAssignableFrom(messageType) || messageType == typeof(IMessage))
{
// messageType is not derived from IMessage
continue;
}
IMessage message = (IMessage)Activator.CreateInstance(messageType);
messageMap.Add(message.Message_ID, messageType);
}
}
public IMessage CreateObject(short Message_ID, params object[] args)
{
return (IMessage)Activator.CreateInstance(messageMap[Message_ID], args);
}
}
}
EDIT to answer comment:
If the "generic" library is the one processing the messages, and it has no knowledge of the types of message is is processing, you obviously have to change that.
Either move to a "plug-in" model where your custom message dlls will be loaded from a specific directory on startup of the generic library, or read the custom message dlls from a config file at startup for the generic library.
// Read customMessageDllName and customMessageClassName from your config file
Assembly assembly = Assembly.Load(customMessageDllName);
IMessage customMessage = (IMessage)assembly.CreateInstance(customMessageClassName);
Why not simply use WCF? You'll get ease of development, great support, as well as interoperability with Java.
Gallactic Jello is on the right path. The part he left out is overcoming the problem of the generic library knowing about classes in the center library, which I have further addressed. I've created a sample solution with three projects, the full contents of which I'll spare you. Here is the gist.
Class Library: Generic lib
Contains a Message_Handler, his own IMessage_Creator, definitions of the interfaces, and an IMessage type of his own.
Class Library: Center Lib
Contains an IMessage_Creator, and his own IMessage type.
Application: Application
has a SVM (static void Main()) containing the following lines of code:
Generic_lib.IMessage msg = Generic_lib.Message_Handler.get_message(2); //a Center Message
if (msg is Center_lib.Center_Message)
{
System.Console.WriteLine("got center message");
}
You will be amazed how important the if statement is!!! I'll explain later
Here's the code in the Type Initializer for Generic_lib.Message_Handler:
static Message_Handler()
{
//here, do the registration.
int registered = 0;
System.Reflection.Assembly[] assemblies = System.AppDomain.CurrentDomain.GetAssemblies();
foreach (System.Reflection.Assembly asm in assemblies)
{
System.Type[] types = asm.GetTypes();
foreach (System.Type t in types)
{
System.Type[] interfaces = t.GetInterfaces();
foreach (System.Type i in interfaces)
{
if (i == typeof(IMessage_Creator))
{
System.Reflection.ConstructorInfo[] constructors = t.GetConstructors();
foreach (System.Reflection.ConstructorInfo ctor in constructors)
{
if (ctor.GetParameters().Length == 0)
{
Add_Creator(ctor.Invoke(new object[0]) as IMessage_Creator);
registered++;
}
}
}
}
}
}
System.Diagnostics.Debug.WriteLine("registered " + registered.ToString() + " message creators.");
}
Horrific, isn't it? First, we get all the assemblies in the current domain, and here's where the if statement comes in. If there was no reference to the 'Center__lib' anywhere in the program, the array of Assemblies won't contain Center_lib. You need to be sure that your reference to it is good. Creating a method that is never called that references it is not enough, a using statement is not good enough,
if (msg is Center_lib.Center_Message) ;
is not enough. It has to be a reference that can't be optimized away. The above are all optimized away (even in Debug mode, specifying `don't optimize.'
I hope someone can come up with an even more elegant solution, but this will have to do for now.
Aaron