Having trouble getting MEF imports to be resolved - c#

This is sort of a continuation of one of my earlier posts, which involves the resolving of modules in my WPF application. This question is specifically related to the effect of interdependencies of modules and the method of constructing those modules (i.e. via MEF or through new) on MEF's ability to resolve relationships.
I have tried two approaches:
left approach: the App implements IError
right approach: the App has a member that implements IError
Left approach
My code behind looked like this (just the MEF-related stuff):
// app.cs
[Export(typeof(IError))]
public partial class Window1 : Window, IError
{
[Import]
public CandyCo.Shared.LibraryInterfaces.IPlugin Plugin { get; set; }
[Import]
public CandyCo.Shared.LibraryInterfaces.ICandySettings Settings { get; set; }
private ICandySettings Settings;
public Window1()
{
// I create the preferences here with new, instead of using MEF. I wonder
// if that's my whole problem? If I use MEF, and want to have parameters
// going to the constructor, then do I have to [Export] a POCO (i.e. string)?
Settings = new CandySettings( "Settings", #"c:\settings.xml");
var catalog = new DirectoryCatalog( ".");
var container = new CompositionContainer( catalog);
try {
container.ComposeParts( this);
} catch( CompositionException ex) {
foreach( CompositionError e in ex.Errors) {
string description = e.Description;
string details = e.Exception.Message;
}
throw;
}
}
}
// plugin.cs
[Export(typeof(IPlugin))]
public class Plugin : IPlugin
{
[Import]
public CandyCo.Shared.LibraryInterfaces.ICandySettings CandySettings { get; set; }
[Import]
public CandyCo.Shared.LibraryInterfaces.IError ErrorInterface { get; set; }
[ImportingConstructor]
public Plugin( ICandySettings candy_settings, IError error_interface)
{
CandySettings = candy_settings;
ErrorInterface = error_interface;
}
}
// candysettings.cs
[Export(typeof(ICandySettings))]
public class CandySettings : ICandySettings
{
...
}
Right-side approach
Basically the same as the left-side approach, except that I created a class that inherits from IError in the same assembly as Window1. I then used an [Import] to try to get MEF to resolve that for me.
Can anyone explain how the two ways I have approached MEF here are flawed? I have been in the dark for so long that instead of reading about MEF and trying different suggestions, I've added MEF to my solution and am stepping into the code. The part where it looks like it fails is when it calls partManager.GetSavedImport(). For some reason, the importCache is null, which I don't understand. All the way up to this point, it's been looking at the part (Window1) and trying to resolve two imported interfaces -- IError and IPlugin. I would have expected it to enter code that looks at other assemblies in the same executable folder, and then check it for exports so that it knows how to resolve the imports...
I had found a mistake in my code, and when I fixed it, the MEF exception changed, and was also more useful. It clearly pointed out that it couldn't find a CandySettings default constructor! And digging more, I found a good post from Glenn Block that discusses this. So I need to finish reading it and see if his workaround will do the trick or not. I would still appreciate more answers, since there's no telling if the workaround is the right thing to do or not.

This post really helped. I hadn't seen this information before, but it totally did the trick for me.
http://mindinthewater.blogspot.com/2010/01/using-mef-with-classes-which-take.html
Basically, my problem was that I needed to pass values to the constructor. All of my past tests involved passing interfaces to other shared libraries, but in my case, I just wanted to pass a couple of strings. I obviously didn't want to try to wrap these strings in an interface just to pass POCOs.
My first attempt in getting around this inconvenience was to do the best I could with the default constructor. I then left it up to fate that a developer would remember to call the Init() method. This was bad for obvious reasons, but I wanted to try it out anyway. In the end, it just didn't work -- the problem here is that MEF wants to resolve imports and exports, but my Init() method wouldn't get called until after composing the parts... so any other dependents of that particular library would end up with a not-truly-initialized instance of the library since Init() won't get called until later.
Anyhow, this trick of importing strings for the constructor parameters worked like a charm.

It would help if you would include the error message that you are getting.
However, if you go with the left approach, I think putting a PartNotDiscoverableAttribute on your Window1 class may fix the problem.
The issue is that the DirectoryCatalog is going to include the assembly that includes Window1, so there is going to be an IError export available from the catalog (and MEF would create an instance of Window1 if you requested that export's value). When you add the Window1 you created via ComposeParts, you are trying to add another IError export to the container. Since your plugin is only requesting a single IError export, it won't work when there is more than one available. Adding the PartNotDiscoverableAttribute on the Window1 class will prevent it from being included in the catalog.

Related

"Type is not defined" when I want to add my custom class as settings type

I want to add this class as setting's type:
using System.Collections.Generic;
using System.Configuration;
namespace MY_PROJECT.SUB_PROJECT
{
[SettingsSerializeAs(SettingsSerializeAs.Xml)]
public class Configs: List<ConfigData>
{
Configs(int capacity): base(capacity) { }
public string GroupName { get; set; }
}
}
So what I did:
Select Browse... in the type dropbox:
I cannot see the MY_PROJECT namespace anywhere:
So I typed the full type manually:
The result is an error:
Type 'MY_PROJECT.SUB_PROJECT.Configs' is not defined.
I also tried SUB_PROJECT.Configs and Configs alone. Nothing helped. Why does my class not show in the browser?
In order to pull something in as a reference you need to have it compiled as a dll file. In Visual Studio they refer to this as a "Library" which is really just a class without a main function. Other option is to just leave it in the same namespace and pull the class into whatever else your working on.
I just had this issue and it was due to an Inconsistent accessibility error. Make sure that any 'required' type/field is globally accessible (public?). For the OP's case, making the constructor public solves the issue:
[SettingsSerializeAs(SettingsSerializeAs.Xml)]
public class Configs: List<ConfigData>
{
public Configs(int capacity): base(capacity) { }
// ^^
public string GroupName { get; set; }
}
In my case this was the problem:
internal struct NativeType
{
//...
}
[SettingsSerializeAs(SettingsSerializeAs.Xml)]
public class NativeTypeWrapper
{
public NativeType type; // This will not work because NativeType
// is less accessible than NativeTypeWrapper...
}
I had this problem as well. I was doing exactly the same: creating a custom class to use in Application Settings. In my case, I followed the steps outlined in this very informative article:
http://www.blackwasp.co.uk/CustomAppSettings.aspx
I should note the article is written for C#, and I painstakingly converted it to VB until it worked. I had to solve the Type...is not defined error the hard way: relentlessly experimenting until I got it to work.
I will describe my first solution, one which was not mentioned in the article, probably because it's for C# instead of VB, and that is: put the custom class or classes each in their own .vb files. For instance: Employee.vb and Room.vb. This is the only way I could make it work perfectly with no errors. After doing this and rebuilding the solution, I was then able to add my custom class as an Application Setting, but of course only by manually typing the full name TestProject.Employee in the Select a Type dialog.
However, following the article I linked above, if I put all the class definitions in the Module1.vb file with Sub Main(), the Select a Type dialog cannot find them, and I receive the Type...is not defined error.
And the cause of this error seems to be shortcomings in the code & design of the Applications Settings system and Settings page of the Project Properties dialog. I say this because of the solution I found: I hacked my classes into the settings the hard way.
What I mean by that is I initially created the setting with the name DefaultEmployee and type of String. Then I used the Find In Files dialog to find all instances of DefaultEmployee and replaced the appropriate instances of String with TestProject.Employee.
The files I made replacements in are: App.config, Settings.Designer.vb, and Settings.settings.
And it worked..! Sort of. I should say the code ran fine and it did what was expected. But...the Application Settings dialog didn't like it. After I made the changes, there are various errors from the Project Properties/Settings system every time I opened it. But as I said, it still works.
Thus...my only conclusion is the coding of the Settings system is not designed to handle this situation, and if you wish to have the most reliable & error-free experience, it's best to put each of the custom classes in their own .vb class file.
On the other hand, if you wish to become very adventurous, you could create your own Applications Settings system, as the author of this article did. I have not read all of this yet, but scanning through it seems very interesting:
https://weblog.west-wind.com/posts/2012/dec/28/building-a-better-net-application-configuration-class-revisited

How to, using dependency injection, get configuration from multiple sources?

I'm using Simple Injector, but maybe what I need is more of a conceptual answer.
Here's the deal, suppose I have an interface with my application settings:
public interface IApplicationSettings
{
bool EnableLogging { get; }
bool CopyLocal { get; }
string ServerName { get; }
}
Then, one would usually have a class which implements IApplicationSettings, getting each field from a specified source, for instance:
public class AppConfigSettings : IApplicationSettings
{
private bool? enableLogging;
public bool EnableLogging
{
get
{
if (enableLogging == null)
{
enableLogging = Convert.ToBoolean(ConfigurationManager.AppSettings["EnableLogging"];
}
return enableLogging;
}
}
...
}
HOWEVER! Let's say I want to get EnableLogging from app.config, CopyLocal from database, and ServerName from another implementation which gets the current computer name. I want to be able to mix-match my app configuration without having to create 9 implementations, one for each combination.
I'm assuming that I can't pass any parameters because the interfaces are resolved by the injector (container).
I thought of this, initially:
public interface IApplicationSettings<TEnableLogging,TCopyLocal,TServerName>
where TEnableLogging : IGetValue<bool>
where TCopyLocal : IGetValue<bool>
where TServerName : IGetValue<string>
{
TEnableLogging EnableLog{get;}
TCopyLocal CopyLocal{get;}
TServerName ServerName{get;}
}
public class ApplicationSettings<TEnableLogging,TCopyLocal,TServerName>
{
private bool? enableLogging;
public bool EnableLogging
{
get
{
if (enableLogging == null)
{
enableLogging = Container.GetInstance<TEnableLogging>().Value
}
return enableLogging;
}
}
}
However, with this I have one main problem: How do I know how to create an instance of TEnableLogging (which is a IGetValue<bool>)? Oh, assume that IGetValue<bool> is an interface which has a Value property, which will be implemented by the concrete class. But the concrete class may need some specifics (like what's the name of the key in app.config) or not (I may simply want to return always true).
I'm relatively new to dependency injection, so maybe I'm thinking in a wrong way. Does anyone have any ideas on how to accomplish this?
(You may answer using another DI library, I won't mind. I think I just need to grab the concept of it.)
You are definitely heading the wrong way here.
Some years ago I built an application that contained an interface much like your IApplicationSettings. I believe I named it IApplicationConfiguration, but it contained all application's configuration values as well.
Although it helped me make my application testable at first, after some time the design started to get in the way. A lot of implementations depended on that interface, but it kept changing a lot and with it the implementation, and the test version.
Just like you I implemented some lazy loading, but this had a terrible down side. When one of the configuration values was missing, I only found out that it did when the value was called for the first time. This resulted in a configuration that was hard to verify.
It took me a couple of iterations of refactoring to find out what the core of the problem was. Big interfaces are a problem. My IApplicationConfiguration class was violating the Interface Segregation Principle and the result was poor maintainability.
In the end I found out that this interface was completely useless. Besides violating the ISP, those configuration values described an implementation detail and instead of making an application wide abstraction, it is much better to supply each implementation directly with the configuration value they need, and only the values they need.
When you do this, the easiest thing to do is to wrap those values into a Parameter Object (even if it is just one value), and inject those configuration values into the constructor. Here's an ecample:
var enableLogging =
Convert.ToBoolean(ConfigurationManager.AppSettings["EnableLogging"]);
container.RegisterSingleton(new LoggerSettings(loggingEnabled: enableLogging));
In this case, LoggerSettings is a configuration object specific to Logger, which requires it as constructor argument.
When doing this, the enableLogging value is read just once from the configuration file and is done so during application startup. This makes it fast and makes it fail at application startup when the value is missing.

Generate .net dll wrapper around existing .net library

I have a dll named ExpensiveAndLargeObfuscatedFoo.dll.
Lets says it defines a type named ExpensiveAndLargeObfuscatedFooSubClass.
It's been compiled for .NET.
Are there any tools (free, paid, whatever) that will generate c# or vb class files that will do nothing but wrap around everything defined in this expensive dll? That way I can add functionality, fix bugs (that CorpFUBAR won't fix), add logging, etc?
Literally, I want output that looks like this
namespace easytoread {
public class SubClass {
private ExpensiveAndLargeObfuscatedFoo.SubClass _originalSubClass;
public SubClass() {
this._originalSubClass = new ExpensiveAndLargeObfuscatedFoo.SubClass ();
}
public string StupidBuggyMethod(string param1,int param2) {
return _originalSubClass.StupidBuggyMethod(param1, param2);
}
}
}
It would have to handle custom return types as well as primitives
namespace easytoread {
public class SubFooClass {
private ExpensiveAndLargeObfuscatedFoo.SubFooClass _originalSubFooClass;
public SubFooClass() {
this._originalSubFooClass= new ExpensiveAndLargeObfuscatedFoo.SubFooClass ();
}
private SubFooClass(ExpensiveAndLargeObfuscatedFoo.SubFooClass orig) {
this._originalSubFooClass = orig;
}
public SubFooClass StupidBuggyMethod(string param1,int param2) {
return new SubFooClass(_originalSubFooClass.StupidBuggyMethod(param1, param2));
}
}
}
And so on and so forth for every single defined class.
Basically, poor mans dynamic proxy? (yay, Castle Project is awesome!)
We'd also like to rename some of our wrapper classes, but the tool doesn't need to do that.
Without renaming, we'd be able to replace the old assembly with our new generated one, change using statements and continue on like nothing happened (except the bugs were fixed!)
It just needs to examine the dll and do code generation. the generated code can even be VB.NET, or ironpython, or anything CLR.
This is a slippery slope and I'm not happy that I ended up here, but this seems to be the way to go. I looked at the Castle Project, but unless I'm mistaken that won't work for two reasons: 1) I can't rename anything (don't ask), 2) none of the assemblies methods are declared virtual or even overridable. Even if they were, there's hundreds of types I'd have to override manually, which doesn't sound fun.
ReSharper can do much of the work for you.
You will need to declare a basic class:
namespace easytoread {
public class SubClass {
private ExpensiveAndLargeObfuscatedFoo.SubClass _originalSubClass;
}
}
Then, choose ReSharper > Edit > Generate Code (Alt+Ins), select "Delegating Members", select all, and let it generate the code.
It won't wrap return values with custom classes (it will return the original type), so that would still have to be added manually.
It seems the best answer is "There is no such tool". So, I'll be taking a stab at writing my own later as an off-hours project. If I ever get something useful working I'll github it and update here.
UPDATE
Visual Studio 2012 Fakes seem to be promising. http://msdn.microsoft.com/en-us/library/tfs/hh549175(v=vs.110).aspx - we've moved on but I might try creating a fake and then dropping it in as a replacement dll sometime in the future
If you have access to the source code, rename and fix in the source
code.
If you don't have access (and you can do it legally) use some
tool like Reflector or dotPeek to get the source code and then,
goto to the first point.

How to ask user for input (through Form) from another class during a loop?

How do I populate a Form from within a method in a class library? So in the example below Method1() is what's it about.
Project "UI", Windows Forms Application
reference to MyLib
public class Form1 : Form
{
...
call some methods from MyLib.MyClass
...
}
Project "MyLib", Class Library
public class MyClass
{
...
public void Method1()
{
loop through an array and ask user to validate some data on the form during each iteration
}
}
UPDATE:
To be more specific, the MyLib library contains a class that will load a .csv file into an array (which for each row will be added to a List<string[]>) and than will loop through the List<string[]> looking for "possible" duplicates. Whenever one is found the user needs to be presented (on a Form) with both records to ultimately decide if they are the same.
How do I populate a Form from within a method in a class library?
The real question is why would you want to? The library should not be responsible for something like this. This is logic specific to your workflow and UI, not something a library is typically used for. The library should provide useful data structures, but things that are specific to your application (like gathering input and deciding what to do with it) should be handled by your code.
Anyway... I feel a bit dirty saying this... you could always just pass a reference to your form type as an argument to the method (an approach that will, among other things, tightly couple the two assemblies, making one unusable without the other)...
shudder
You may use Cross/Circular-referencing but this is not advisable due to several reasons.
You may also declare a Form-type object(better if static) within the class library and pass that form as reference and you may call the child controls within that referenced variable through the member "Controls" if I'm not mistaken.
Even though Ed put that final comment in, DO NOT DO IT! Of course it's possible, but it makes no sense. Resist the temptation!
The library should implement some general functionality, i.e. provide data structures, logic methods or maybe P/Invoke methods. But in your form class is where the logical for your UI goes. Just make a method in Form1 to handle the validation. It would be a lot easier and a lot clearer.
It's a vast question.
The easiest way would be to add a reference to System.Windows.Forms in your class lib. Then, pass the window as an argument to your business class.
But although easy this solution is, it's not a clean way. In a clean layered architecture, you can't use objects of upper layers in lowers layers. It can be both a challenge to compile and a maintenance black hole. Moreover, unit testing such cases are complex.
Considering this, another solution, a bit more complex, would be to use inversion of control, using a framework like Unity, Mef or any other, or even doing it manually.
The main idea would be to create in your class library an interface that defines user interactions like this :
public interface IInputValidator {
bool IsValid(MyClass itemToValidate);
}
Then, in you windows form application, implement this interface :
public class Form1 : Form, IInputValidator {
public void CallBusinessClass() {
var myObj = new BusinessClass(this); // the key of the concept is here
myObj.Iterate();
}
public bool IsValid(MyClass itemToValidate) {
return MessageBox.Show("Is valid ?", MessageBoxButtons.YesNo) == MessageBoxButtons.Yes);
}
}
Then, in you business class :
public class BusinessClass {
private IInputValidator m_validator;
public BusinessClass(IInputValidator validator) {
this.m_validator = validator;
}
public void Iterate()
{
foreach(var item in ItemsToIterate)
{
var isValid = m_validator.IsValid(item); // call the upper layer from a lower layer
}
}
}
hope that helps

Design for Cross-Platform Classes in C#

Summary: I want to know the best design for creating cross-platform (eg. desktop, web, and Silverlight) classes in C#, with no duplication of code, with the pros and cons of each design.
I'm often writing new, useful classes for one application domain; there's no reason why they won't work across domains. How can I structure my code to make it ideally cross-platform?
For example, let's say I wanted to make a generic "MyTimer" class with an interval and on-tick event. In desktop, this would use the built-in .NET timer. In Silverlight, I would use a DispatchTimer.
Design #1 might be "create a class and use pre-processor directives for conditional compilation," eg. "#IF SILVERILGHT ...". However, this leads to code that is less understandable, readable, and maintainable.
Design #2 might be "create subclasses called DesktopTimer and SilverlightTimer and consume those from MyTimer." How would that work?
While this is a trivial case, I may have more complicated classes that, for example, consume platform-specific classes (IsolatedStorage, DispatchTimer, etc.) but aren't directly replacing them.
What other designs/paradigms can I use?
I would suggest writing Interfaces that you would simply implement for your platform specific code. Then, the interfaces assure that your code will respect the contracts given by your interface, otherwise there will be a code break (if one member is not implemented).
Besides, within this library where resides your specific timer classes, to stick to your example, I would create a class for each platform, thus using the DispatchTimer for Silverlight, and the built-in .NET timer for the desktop version.
In the end, you would end up using only one interface that only its implementers know how to deal with the contract specifically to your underlying platform.
EDIT #1
Conditonal design is not an option for a good design. Here is a tool that will help you deal with the Dependancy Injection, that is called Unity Application Block, and is used to deal with such scenario like yours.
You only use an XML configuration that is very versatile to "tell" what has to be instantiated when this or that interface is needed. Then, the UnityContainer consults with the configuration you have made, and instantiate the right class for you. This assures good design approach and architecture.
EDIT #2
I'm not very familiar with Dependency Injection, and not at all familiar with Unity Application Block. Can you point to some resources or explain these a bit further?
Microsoft Enterprise Library 5.0 - April 2010;
Microsoft Unity 2.0 – April 2010;
Microsoft Unity 2.0 Documentation for Visual Studio 2008;
Are there good tutorial/walkthroughs for unity that don't use configuration files? (SO question on the topic that should provide valuable hints to start with Unity);
Specifying Types in the Configuration File;
Walkthrough: The Unity StopLight QuickStart;
Walkthrough: The Unity Event Broker Extension QuickStart.
I think these resources shall guide you through your learnings. If you need further assistance, please let me know! =)
EDIT #3
But anyway, the StopLight quickstart [...] seems to imply that the dependency mapping of interface to concrete class is done in code (which won't work for me).
In fact, you can do both code and XML dependency mapping, the choice is yours! =)
Here are some example that you should perhaps inspire from to make the StopLight quickstart use the XML configuration instead of the coded mapping.
Testing Your Unity XML Configuration;
Using Design-Time Configuration;
Source Schema for the Unity Application Block.
If this doesn't help you get through, let me know. I shall then provide a simple example using XML dependency mapping. =)
1) Interfaces with platform-specific class in their own assemblies: ITimer in a shared assembly, and a "WebAssembly" containing WebTimer, for example. Then the "WebAssembly.dll", or "DesktopAssembly.dll" are on-demand loaded. This turns it into more of a deployment/configuration issue, and everything compiles. Dependency Injection or MEF become a great help here.
2) Interfaces (again), but with conditional compilation. This makes it less of a deployment issue, and more of a compilation problem. WebTimer would have #ifdef WEB_PLATFORM around it, and so on.
Personally, I'd lean to #1 - but in a complicated application, most likely you'll end up having to use both because of slight changes in the available parts of the .net framework between silverlight and everything else. You may even want different behavior in core parts of your app just for the performance issues.
I think interfaces are a good choice here (defining what a timer will do without actually implementing it)
public interface ITimer
{
void CreateTimer(int _interval, TimerDelegate _delegate);
void StopTimer();
// etc...
} // eo interface ITimer
From this, you derive your concrete timers:
public class DesktopTimer : ITimer
{
} // eo DesktopTimer
public class SilverlightTimer : ITimer
{
} // eo class SilverlightTimer
public class WebTimer : Timer
{
} // eo class WebTimer
Then comes the fun part. How do we create the right timer? Here you could implement some kind of platform-factory that returned the right timer depending on what platform it is running on. Here is a quick and dirty idea (I would make it more dynamic than this, and perhaps implement one factory for multiple kinds of classes, but this is an example)
public enum Platform
{
Desktop,
Web,
Silverlight
} // eo enum Platform
public class TimerFactory
{
private class ObjectInfo
{
private string m_Assembly;
private string m_Type;
// ctor
public ObjectInfo(string _assembly, string _type)
{
m_Assembly = _assembly;
m_Type = _type;
} // eo ctor
public ITimer Create() {return(AppDomain.CurrentDomain.CreateInstanceAndUnwrap(m_Assembly, m_Type));}
} // eo class ObjectInfo
Dictionary<Platform, ObjectInfo> m_Types = new Dictionary<PlatForm, ObjectInfo>();
public TimerFactory()
{
m_Types[Platform.Desktop] = new ObjectInfo("Desktop", "MyNamespace.DesktopTimer");
m_Types[Platform.Silverlight] = new ObjectInfo("Silverlight", "MyNameSpace.SilverlightTimer");
// ...
} // eo ctor
public ITimer Create()
{
// based on platform, create appropriate ObjectInfo
} // eo Create
} // eo class TimerFactory
As I mentioned above, I would not have a factory for every time of object, but make a generic platform-factory that could handle timers, containers and whatever else you want. This is just an example.
The Model-View-Presenter pattern is a really good approach if you want to separate all of your user interface logic from the actual GUI framework you are using. Read Michael Feather's article "The Humble Dialog Box" to get an excellent explanation of how it works:
http://www.objectmentor.com/resources/articles/TheHumbleDialogBox.pdf
The original article was made for C++, if you want a C# example, look here:
http://codebetter.com/blogs/jeremy.miller/articles/129546.aspx
The Pros are:
you will make your GUI logic resusable
your GUI logic becomes applicable for unit testing
The Cons:
if your program does not need more than one GUI framework, this approach produces more lines-of-code, and you have to deal with more complexity, since you have to decide all through your coding which parts of your code belong into the view and which into the presenter
Go with all OOD you know. I'd suggest creating platform-agnostic (Windows, Mono/destkop, web) domain model. Use abstract classes to model platform-dependant stuff (like the Timer). Use Dependency Injection and/or Factory patterns to use specific implementations.
EDIT: at some point you have to specify what concrete classes to use, but using the abovementioned patterns can bring all that code into one place without using conditional compilation.
EDIT: an example of DI/Factory. Of course you can use on of existing frameworks, which will give you more power and expressivenes. For the simple example it seems like an overkill, but the more complicated the code, the bigger the gain of using the patterns.
// Common.dll
public interface IPlatformInfo
{
string PlatformName { get; }
}
public interface PlatformFactory
{
IPlatformInfo CreatePlatformInfo();
// other...
}
public class WelcomeMessage
{
private IPlatformInfo platformInfo;
public WelcomeMessage(IPlatformInfo platformInfo)
{
this.platformInfo = platformInfo;
}
public string GetMessage()
{
return "Welcome at " + platformInfo.PlatformName + "!";
}
}
// WindowsApp.exe
public class WindowsPlatformInfo : IPlatformInfo
{
public string PlatformName
{
get { return "Windows"; }
}
}
public class WindowsPlatformFactory : PlatformFactory
{
public IPlatformInfo CreatePlatformInfo()
{
return new WindowsPlatformInfo();
}
}
public class WindowsProgram
{
public static void Main(string[] args)
{
var factory = new WindowsPlatformFactory();
var message = new WelcomeMessage(factory.CreatePlatformInfo());
Console.WriteLine(message.GetMessage());
}
}
// MonoApp.exe
public class MonoPlatformInfo : IPlatformInfo
{
public string PlatformName
{
get { return "Mono"; }
}
}
public class MonoPlatformFactory : PlatformFactory
{
public IPlatformInfo CreatePlatformInfo()
{
return new MonoPlatformInfo();
}
}
public class MonoProgram
{
public static void Main(string[] args)
{
var factory = new MonoPlatformFactory();
var message = new WelcomeMessage(factory.CreatePlatformInfo());
Console.WriteLine(message.GetMessage());
}
}
As others have sugested, interfaces are the way to go here. I would alter the interface from sugestion Moo-Juice suggestion slightly...
`
//Why is this block not formated like code???
public interface ITimer{
void StopTimer(); // etc...
void StartTimer(); // etc...
TimeSpan Duration {get;} // eo interface ITimer
}`
Now you would need to get the ITimer into your class that is using it. The most timple way to do this is called dependency injection. The most common approach to achieve this is called constructor injection.
So when creating a class that needs a timer you pass a timer into the class when creating one.
Basically you do:
var foo = new Foo(new WebTimer());
Since that will get complicated quite fast, you can utilize some helpers. This pattern is called inversion of control. There are some frameworks that will help you, like the ninject or castle windsor.
Both are inversion of control (IOC) containers. (Thats the secret sauce)
Basically you "register" your timer in the IOC, and also register your "Foo". When you need a "Foo", you ask your IOC Container to create one. The container looks at the constructor, finds that it needs a ITimer. It will then create an ITimer for you, and pass it into the constructor, and finally hand you the complete class.
Inside you class you dont need to have any knowledge about the ITimer, or how to create it, since all that was moved to the outside.
For different Applications you now only need to register the correct components, and you are done...
P.s.: Be carefull and dont confuse the IOC Container with a service locator...
Links:
http://ninject.org/download
http://www.castleproject.org/container/index.html
http://www.pnpguidance.net/Category/Unity.aspx
Why not have configuration section which will tell your library about the platform of the host application. This you have to set only once in your application to the host config file (web.config or app.config), and rest you can use using Factory method as suggested by Moo-Juice. You can use platform detail over entire functionality of the library.

Categories

Resources