MEF Import Scenario - c#

Hi
I have some problems in import scenarios example:
[Export(typeof(IICon))]
public class WriteInputData : IICon
{
[Import(typeof(IIOWriter))]
public IIOWriter IOWriter { get; set; }
public object Input { get; set; }
public void Process()
{
IOWriter.Write(Input);
}
}
Then i hawe two classes that implement interface IIOWriter like :
[Export(typeof(IIOWriter))]
public class FileWriter : IIOWriter
{
public string FilePath { get; set; }
public void Write(object data)
{
if (string.IsNullOrEmpty(FilePath))
FilePath = #"c:\test.txt";
var fl = new StreamWriter(FilePath, true);
fl.Write((string)data);
fl.Flush();
fl.Close();
}
public string Name
{
get { return "FileWriter"; }
}
}
[Export(typeof(IIOWriter))]
public class ConsoleWrite : IIOWriter
{
public void Write(object data)
{
Console.WriteLine((string)data);
}
public string Name
{
get { return "ConsoleWrite"; }
}
}
How can i let that to user so he can change that in runtime, so example whene he type select in ListBox FileWriter than the IIOWriter in WriteInputData will be injected FileWriter end so one..
Sorry for my bad english.

You probably need to supply some metadata to the export, such like:
[Export(typeof(IIOWriter)),
ExportMetadata("Name", "ConsoleWriter")]
public class ConsoleWriter : IIOWriter
{
}
The reason you need to do this, is that you need to know ahead of time what the user selection will match to. Because of this, you may want to refactor your design to remove the dependency on the IOWriter property:
[Export(typeof(IICon))]
public class WriteInputData : IICon
{
public object Input { get; set; }
public void Process(IIOWriter writer)
{
}
}
If you define your Process method to take in an instance, we can resolve it using the CompositionContainer. Firstly, define a metadata interface that matches your ExportMetadata value:
public interface INamedMetadata
{
string Name { get; }
}
And then, we can resolve the instance:
public IIOWriter GetWriter(string name)
{
return container
.GetExports<IIOWriter, INamedMetadata>()
.Where(e => e.Metadata.Name.Equals(name, StringComparison.OrdinalIgnoreCase))
.Select(e => e.Value)
.FirstOrDefault();
}
Hope that points you in the right direction....

Related

C# Generic way to store unknown properties in List

I'd like to store LicenseInformations for multiple domains in my application.
The structure looks the following way:
public class LicenseData
{
// properties...
public List<LicenseDomain> Domains { get; set; }
// other properties...
}
public class LicenseDomain
{
// properties...
public object LicenseConfig { get; set; }
}
We have multiple domains with total different properties, but the license may contain multiple configurations..
For example:
{
"MaxValidUsers": 5
}
{
"Property": "xy"
"SubProperty": { "Foo" : "Bar"
}
}
The generation is no problem in any way..
But if I restore the informations from my signed json file I deserialize to object..
Which pattern / possiblity I have to work with Interfaces / Abstracts / that I can (RE)store generic informations here..
Right now I hack with:
JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(domain.LicenseConfig))
But I can't agree with myself.
So, based on the pieces of context I can grab, I would actually recommend having your LicenseConfig stored as a JSON string, which would give you the ability to do something like this:
public class LicenseDomain
{
// properties...
// Depending on how this is loaded,
// this property (or at least its setter) could be made private/protected/internal
public string LicenseConfigJson { get; set; }
public T LicenseConfig<T>() where T : BaseLicenseConfig
{
if (string.IsNullOrWhiteSpace(LicenseConfigJson))
{
return null;
}
return JsonConvert.DeserializeObject<T>(LicenseConfigJson);
}
public void SaveLicenseConfig<T>(T config) where T : BaseLicenseConfig
{
if (config == null)
{
LicenseConfigJson = null;
}
else
{
LicenseConfigJson = JsonConvert.SerializeObject(config);
}
}
}
Or if each LicenseDomain can only have one type of LicenseConfig, you could make it a generic parameter to the class:
public class LicenseData
{
// properties...
public List<LicenseDomain<BaseLicenseConfig>> Domains { get; set; }
// other properties...
}
public class LicenseDomain<T> where T : BaseLicenseConfig
{
// properties...
// Depending on where this value comes from, you could do this a variety of ways,
//but this is just one
public string LicenseConfigJson { get; set; }
public T LicenseConfig
{
get
{
if (string.IsNullOrWhiteSpace(LicenseConfigJson))
{
return null;
}
return JsonConvert.DeserializeObject<T>(LicenseConfigJson);
}
set
{
if (value == null)
{
LicenseConfigJson = null;
}
else
{
LicenseConfigJson = JsonConvert.SerializeObject(value);
}
}
}
}
public abstract class BaseLicenseConfig
{
}
public class LicConfig1 : BaseLicenseConfig
{
public int MaxValidUsers { get; set;}
}
public class LicConfig2 : BaseLicenseConfig
{
public string Property {get;set;}
public SubProp SubProperty {get;set;}
}
public class SubProp
{
public string Foo {get;set;}
}
In both cases, the BaseLicenseConfig class is strictly to enforce that everything in the domain list can come from a base class of some kind. If that's not important, you don't need the base class and can remove the where T : BaseLicenseConfig from LicenseDomain class.

C# instantiate class with varying "child" class

I have a class that has some derived classes. That works.
I want to instantiate the "parent" class. Got that far...
But I want to instantiate it with one of the "child" classes, and then possibly change that "child" class later. Maybe the deriving is inappropriate here.
Take the following example:
public class Unicorn {
public string Horn { get; set; }
public Unicorn(){
}
}
public class BadUnicorn : Unicorn{
public string Rainbow()
{
return "dark rainbow";
}
}
public class GoodUnicorn : Unicorn{
public string Rainbow()
{
return "light rainbow";
}
}
I could instantiate one of the children, but then if I change one from "good" to "bad", I would have to re-instantiate. And maybe that's just the way it is, and that would be an acceptable answer if that's all there is to it.
I rather want to instantiate a Unicorn, and then be able to change it from Good to Bad to maintain information stored on that Unicorn, but have access to the current methods and properties of the "child" class.
That way when I call Unicorn.Rainbow() it calls the desired method of the "child" class.
I'm a little new to C#, is there a pattern that fits this bill?
You can't do what you want with polymorphism. You cannot change an instance of class from one to another. Once it is created it is always the same type.
You can use composition though.
Here's what you'd need to do:
public class Unicorn
{
public string Horn { get; set; }
public Unicorn(Rainbow rainbow)
{
_rainbow = rainbow;
}
public void SetRainbow(Rainbow rainbow)
{
_rainbow = rainbow;
}
private Rainbow _rainbow;
public string Rainbow()
{
return _rainbow.Colour();
}
}
public abstract class Rainbow
{
public abstract string Colour();
}
public class BadRainbow : Rainbow
{
public override string Colour()
{
return "dark rainbow";
}
}
public class GoodRainbow : Rainbow
{
public override string Colour()
{
return "light rainbow";
}
}
You can test like this:
var unicorn = new Unicorn(new GoodRainbow());
Console.WriteLine(unicorn.Rainbow());
unicorn.SetRainbow(new BadRainbow());
Console.WriteLine(unicorn.Rainbow());
This outputs:
light rainbow
dark rainbow
The instance of Unicorn stays the same, but you can change the rainbow.
Here's my take on delegate dictionary. While it seems superfluous to use Func instead of just string, if the method have additional functionality like calculation or need parameters, you're covered with Func.
public class Unicorn
{
static Dictionary<Attitude, Func<string>> RainbowByAttitude =
new Dictionary<Attitude, Func<string>>()
{
[Attitude.Bad] = new Func<string>(() => "dark rainbow"),
[Attitude.Good] = new Func<string>(()=>"light rainbow")
};
public string Horn { get; set; }
public enum Attitude
{
Good,Bad
}
public Attitude attitude;
public Unicorn(Attitude attitude)
{
this.attitude = attitude;
}
public string Rainbow() => RainbowByAttitude[attitude].Invoke();
}
class Program
{
static void Main(string[] args)
{
Unicorn unicorn;
unicorn = new Unicorn(Unicorn.Attitude.Bad);
Console.WriteLine(unicorn.Rainbow());
unicorn.attitude = Unicorn.Attitude.Good;
Console.WriteLine(unicorn.Rainbow());
}
}
It seems like a state pattern to me like this:
public abstract class UnicornState
{
public abstract UnicornState Change();
public abstract string Rainbow();
}
public sealed class GoodUnicornState : UnicornState
{
public override UnicornState Change()
{
return new BadUnicornState();
}
public override string Rainbow()
{
return "light rainbow";
}
}
public sealed class BadUnicornState : UnicornState
{
public override UnicornState Change()
{
return new GoodUnicornState();
}
public override string Rainbow()
{
return "dark rainbow";
}
}
public class Unicorn
{
public string Horn { get; set; }
public UnicornState State { get; set; }
public string Rainbow => State.Rainbow();
}
Usage:
var u = new Unicorn();
u.State = new GoodUnicornState();
Console.WriteLine(u.Rainbow);
u.State = u.State.Change();
Console.WriteLine(u.Rainbow);

Generic property-list with any generic argument

I need to instantiate a list-property where the generic type can be anything.
So my Main-method looks like this: (In real, ParsingObject<T> are objects I get from a service)
public static void Main()
{
Parser parser = new Parser();
parser.AddAnObject(
new ParsingObject<int>{PropertyName = "FirstProperty", Active=true, DefaultValue=1}
);
parser.AddAnObject(
new ParsingObject<bool>{PropertyName = "SecondProperty", Active=false, DefaultValue=false}
);
parser.Parse();
}
ParsingObject gets any type (I think only string, bool, int,...) as generic. Now in my parser I need to add this object into a List<ParsingObject<T>> like:
public class Parser
{
private readonly List<ParsingObject<T>> _listOfObjects = new List<ParsingObject<T>>();
public void AddAnObject<T>(ParsingObject<T> item)
{
_listOfObjects.Add(item);
}
public void Parse()
{
foreach(var item in _listOfObjects.Where(w=>Active))
{
DoSomething(item);
}
}
}
but I know, I cannot set T as generic argument when instantiating the list (compiler is crying..).
So I could solve this with using ArrayList - but then I can't access the properties of each object. (See the Parse()-method)
for completeness, here is my ParsingObject<T>-class:
public class ParsingObject<T>
{
public string PropertyName { get; set; }
public bool Active { get; set; }
public T DefaultValue { get; set; }
}
Any idea how I could solve this? I cannot modify the ParsingObject<T>-class.
Depending on what exactly is your end goal, maybe something like this would be sufficient:
public class ParsingObjectBase
{
public string PropertyName { get; set; }
public bool Active { get; set; }
public Type ValueType { get; protected set; }
public object DefVal { get; protected set; }
}
public class ParsingObject<T> : ParsingObjectBase
{
public object DefaultValue
{
get { return (T)DefVal; }
set { DefVal = value; }
}
public ParsingObject()
{
ValueType = typeof(T);
}
}
private readonly List<ParsingObjectBase> _listOfObjects = new List<ParsingObjectBase>();
public void AddAnObject<T>(ParsingObject<T> item)
{
_listOfObjects.Add(item);
}
public void Parse()
{
foreach(var item in _listOfObjects.Where(w=>w.Active))
{
DoSomething(item); //do what exactly?
}
}
You obviously can't do without casting either to concrete ParsingObject<T> or DefVal value in this case, but you have Type information stored in one place and have access to your specific properties. Maybe changing ValueType to some kind of enum would be easier to use with switch?

Get AdditionalValues from containerType's instance

I have something like that:
[ViewTerms]
public class Foo
{
[Term]
public string Name { get; set; }
}
my ViewTermAttribute sets some additional values in ModelMetaData:
public class ViewTermsAttribute : Attribute, IMetadataAware
{
public void OnMetadataCreated(ModelMetadata metadata)
{
metadata.AdditionalValues["values"] = someValues;
}
}
and what I need is to get this info from my 'Name' property:
public class TermAttribute : Attribute, IMetadataAware
{
public void OnMetadataCreated(ModelMetadata metadata)
{
containerAdditionalValues = //need to get here;
}
}
Is possible to get values from instance of the container?

List a classes generic interface names

I have this c# code;
case "Cafe":
source.trendItem = new TrendingLocation<ITrendingCafe>();
break;
case "Pub":
source.trendItem = new TrendingLocation<ITrendingPub>();
break;
etc
a trendItem is defined like this;
public class TrendingItem<T> where T : ITrendingItem
{
public T trendItem { get; set; }
}
Then I have this;
public List<TrendingItem<ITrendingItem>> trendItems { get; set; }
Now for each item in the above trendItems i want to get the interfaces.
I tried using;
string g = fvm.trendItems[4].trendItem.GetType().GetInterfaces()[1].Name;
and
string g = typeof(TrendingLocation<>).GetInterfaces()[0].Name;
but neither of these lists the Generic interface such as ITrendingCafe, ITrendingRestaurant etc.
Is there a way I can get the name of the generic interface name?
You want to use the Type's GetGenericArguments method.
If I understand your structure, it will be something like:
Type[] typeArguments = fvm.trendItems[4].trendItem.GetType().GetGenericArguments();
foreach (Type tParam in typeArguments)
{
// Compare the type with the interface you are looking for.
}
I take it that ITrendingCafe is an interface that implements ITrendingItem. I wrote a quick program that takes and displays all of the interfaces that T Implements:
using System;
using System.Collections.Generic;
namespace TestConsoleApplication
{
public interface ITrendingItem
{
string ItemName { get; set; }
}
public interface ITrendingCafe : ITrendingItem
{
string CafeName { get; set; }
}
public class TrendingItem<T> where T : ITrendingItem
{
public T trendItem { get; set; }
}
public class Cafe : ITrendingCafe
{
public string ItemName { get; set; }
public string CafeName { get; set; }
}
class Program
{
static void Main(string[] args)
{
var test = new List<TrendingItem<ITrendingItem>> { new TrendingItem<ITrendingItem> { trendItem = new Cafe() } };
foreach (var trendingItem in test[0].trendItem.GetType().GetInterfaces())
{
Console.Out.WriteLine(trendingItem.Name);
}
Console.ReadKey();
}
}
}
And here is the output:
As you can see, the interface is there. Just loop through and find the one you need!

Categories