I'm new to MEF. I'm wondering when to initialize instances through composition rather than calling their constructor. For example I'm not sure how to approach the following problem in MEF. If Manager class is in a another DLL and referenced in Program
class Program
{
static void Main(string[] args)
{
var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
var container = new CompositionContainer(catalog);
var manager= container.GetExportedValue<Manager>();
container.ComposeParts(manager);
var letter = manager.Letter;
Console.ReadKey();
}
}
//Manager Class is Business Access Layer referenced to Program as DLL
[Export]
public class Manager
{
private Letter _letter;
[Import]
public Letter Letter
{
get { return _letter ?? (_letter = InitializeComposeLetter()); }
}
private Letter InitializeComposeLetter()
{
var attachments = new List<string>();
var details = new StringBuilder();
var attachmentDirectory = ConfigurationManager.AppSettings["attachmentsDirectory"];
var letterPath = ConfigurationManager.AppSettings["letterPath"];
if (Directory.Exists(attachmentDirectory))
{
var files = Directory.EnumerateFiles(attachmentDirectory);
attachments = files.ToList();
}
if (File.Exists(letterPath))
{
var lines = File.ReadAllLines(letterPath);
foreach (var line in lines)
{
details.Append(line);
details.Append(Environment.NewLine);
}
}
//*********************QUESTION IS HERE *************//
var letter = new Letter() //SHOULD I MEF THIS OUT ??? IF SO HOW??
{
Subject = ConfigurationManager.AppSettings["defaultEmailTitle"],
Details = details.ToString(),
Attachments = attachments,
};
return letter;
}
}
Since you are not using auto-implemented properties, you should import the field instead of the property:
[Import]
private Letter _letter;
Note that if there is not part of type Letter, the composition of Manager will fail. If you want to handle it yourself (as is shown from your code sample) you can use the ImportAttribute.AllowDefault property:
[Import(AllowDefault = true)]
private Letter _letter;
Finally you do not need the call to ComposeParts. This is needed for objects that you have created. If the object is created by the container the composition is done behind the scenes.
So for objects that you create:
var manager = new Manager();
container.ComposeParts(manager);
otherwise:
var manager= container.GetExportedValue<Manager>();
Note that GetExportedValue will throw if the composition fails. There are other GetExportXXX methods that will not throw. Choose one depending on your needs.
Related
I have a class with a get-only collection property. I would like to initialize the collection with the values from an existing collection.
I know that it is possible to initialize the collection using a collection initializer. I could also create the object and then use AddRange on the collection to add the items of the existing collection. This would however create the object with an empty list and add the existing items afterwards.
Is there a way to create the object with the List properly initialized in the first place (without adding a constructor, of course)?
using System.Collections.Generic;
namespace EmptyConsoleApp
{
internal class Program
{
public static void Main(string[] args)
{
// Compiles, but is not what I need
var firstHolder = new Holder()
{
TheList = {"A", "B"}
};
// Compiles, but initializes the list after object creation
var existingList = new List<string>() {"Foo", "Bar"};
var secondHolder = new Holder();
secondHolder.TheList.AddRange(existingList);
// Does not compile
var thirdHolder = new Holder()
{
TheList = {existingList}
};
}
}
internal class Holder
{
public Holder()
{
TheList = new List<string>();
}
public List<string> TheList { get; }
}
}
No. You can't assign this read-only property from a collection initializer. It is read-only after all.
TheList = { "A", "B" } works since it calls Add on TheList (once for each item added), it doesn't create and assign a new instance, which it is not allowed to.
TheList = { existingList } doesn't work since there is a typing issue (TheList = { existingList[0] } does work).
The best option you have it to create a constructor parameter and drop your idea of using collection initializers for something it isn't fit for.
Is there a way to create the object with the List properly initialized in the first place (without adding a constructor, of course)?
No
It's not. That's what a constructor does. If you don't want to do it in the constructor, there is no way to do it.
it is not possible to initialize a read only property from outside of the class itself.
collection initializer is just a simplified syntax version and it does not mean using this syntax you have the same access as if you are in the class constructor
thirdHolder.TheList = existingList; // this is the traditional way
Perhaps you can use factory class pattern like this
internal class Program
{
public static void Main(string[] args)
{
// Compiles, but is not what I need
var firstHolder = new Holder()
{
TheList = { "A", "B" }
};
// Compiles, but initializes the list after object creation
var existingList = new List<string>() { "Foo", "Bar" };
var secondHolder = new Holder();
secondHolder.TheList.AddRange(existingList);
// Does not compile
//var thirdHolder = new Holder()
//{
// TheList = existingList
//};
//thirdHolder.TheList = existingList; // this is the traditional way
var thirdHolder = Holder.HolderFactory(existingList);
}
}
internal class Holder
{
public Holder()
{
TheList = new List<string>();
}
public static Holder HolderFactory(List<string> theList)
{
return new Holder(theList);
}
private Holder(List<string> theList)
{
this.TheList = theList;
}
public List<string> TheList { get; }
}
I have a method I am attempting to Unit Test which makes use of HttpContext.Current.Server.MapPath as well as File.ReadAllLines as follows:
public List<ProductItem> GetAllProductsFromCSV()
{
var productFilePath = HttpContext.Current.Server.MapPath(#"~/CSV/products.csv");
String[] csvData = File.ReadAllLines(productFilePath);
List<ProductItem> result = new List<ProductItem>();
foreach (string csvrow in csvData)
{
var fields = csvrow.Split(',');
ProductItem prod = new ProductItem()
{
ID = Convert.ToInt32(fields[0]),
Description = fields[1],
Item = fields[2][0],
Price = Convert.ToDecimal(fields[3]),
ImagePath = fields[4],
Barcode = fields[5]
};
result.Add(prod);
}
return result;
}
I have a Unit Test setup which (as expected) fails:
[TestMethod()]
public void ProductCSVfileReturnsResult()
{
ProductsCSV productCSV = new ProductsCSV();
List<ProductItem> result = productCSV.GetAllProductsFromCSV();
Assert.IsNotNull(result);
}
I have since done a lot of reading on Moq and Dependancy Injection which I just dont seem to be able to implement. I have also seen a few handy answers on SO such as: How to avoid HttpContext.Server.MapPath for Unit Testing Purposes however I am just unable to follow it for my actual example.
I am hoping someone is able to take a look at this and tell me exactly how I might go about implementing a successful test for this method. I feel I have a lot of the background required but am unable to pull it all together.
In its current form, the method in question is too tightly coupled to implementation concerns that are difficult to replicate when testing in isolation.
For your example, I would advise abstracting all those implementation concerns out into its own service.
public interface IProductsCsvReader {
public string[] ReadAllLines(string virtualPath);
}
And explicitly inject that as a dependency into the class in question
public class ProductsCSV {
private readonly IProductsCsvReader reader;
public ProductsCSV(IProductsCsvReader reader) {
this.reader = reader;
}
public List<ProductItem> GetAllProductsFromCSV() {
var productFilePath = #"~/CSV/products.csv";
var csvData = reader.ReadAllLines(productFilePath);
var result = parseProducts(csvData);
return result;
}
//This method could also eventually be extracted out into its own service
private List<ProductItem> parseProducts(String[] csvData) {
List<ProductItem> result = new List<ProductItem>();
//The following parsing can be improved via a proper
//3rd party csv library but that is out of scope
//for this question.
foreach (string csvrow in csvData) {
var fields = csvrow.Split(',');
ProductItem prod = new ProductItem() {
ID = Convert.ToInt32(fields[0]),
Description = fields[1],
Item = fields[2][0],
Price = Convert.ToDecimal(fields[3]),
ImagePath = fields[4],
Barcode = fields[5]
};
result.Add(prod);
}
return result;
}
}
Note how the class now is not concerned with where or how it gets the data. Only that it gets the data when asked.
This could be simplified even further but that is outside of the scope of this question. (Read up on SOLID principles)
Now you have the flexibility to mock the dependency for testing at a high level, expected behavior.
[TestMethod()]
public void ProductCSVfileReturnsResult() {
var csvData = new string[] {
"1,description1,Item,2.50,SomePath,BARCODE",
"2,description2,Item,2.50,SomePath,BARCODE",
"3,description3,Item,2.50,SomePath,BARCODE",
};
var mock = new Mock<IProductsCsvReader>();
mock.Setup(_ => _.ReadAllLines(It.IsAny<string>())).Returns(csvData);
ProductsCSV productCSV = new ProductsCSV(mock.Object);
List<ProductItem> result = productCSV.GetAllProductsFromCSV();
Assert.IsNotNull(result);
Assert.AreEqual(csvData.Length, result.Count);
}
For completeness here is what a production version of the dependency could look like.
public class DefaultProductsCsvReader : IProductsCsvReader {
public string[] ReadAllLines(string virtualPath) {
var productFilePath = HttpContext.Current.Server.MapPath(virtualPath);
String[] csvData = File.ReadAllLines(productFilePath);
return csvData;
}
}
Using DI just make sure that the abstraction and the implementation are registered with the composition root.
The use of HttpContext.Current makes you assume that the productFilePath is runtime data, but in fact it isn't. It is configuration value, because it _will not change during the lifetime of the application. You should instead inject this value into the constructor of the component that needs it.
That will obviously be a problem in case you use HttpContext.Current, but you can call HostingEnvironment.MapPath() instead; no HttpContext is required:
public class ProductReader
{
private readonly string path;
public ProductReader(string path) {
this.path = path;
}
public List<ProductItem> GetAllProductsFromCSV() { ... }
}
You can construct your class as follows:
string productCsvPath = HostingEnvironment.MapPath(#"~/CSV/products.csv");
var reader = new ProductReader(productCsvPath);
This doesn't solve the tight coupling with File, but I'll refer to Nkosi's excellent answer for the rest.
I don't really find a good title for this question but it goes as follows. I find myself in a situation where I want to identify a class and an instance of the class. The solution I have is to use a const value for the class and a property that returns that const value for the instance.
I don't know if there is a better solution. It feels a bit strange that I need two ways to identify and just reuse the value. Is there a better way?
Pseudo code below. In the real application there will be more classes that derive from the base class and the objects list will contain instances of these as well. Deserialization happens at startup, serialization at shutdown after after the list has been altered due to user activity.
static void Main(string[] args)
{
List<Base> objects = new List<Base>();
List<string> serializationIds = new List<string>();
// SerializationIds initialized somehow
foreach (var serializationId in serializationIds)
{
switch(serializationId)
{
// Identify class
case Derived.SerializationIdText:
objects.Add(new Derived());
break;
}
}
// add remove objects
foreach (var item in objects)
{
// Identify instance
string serializationId = item.SerializationId;
// Do something with serializationId;
}
}
public abstract class Base
{
public string SerializationId { get; set; }
}
public class Derived : Base
{
public const string SerializationIdText = "DatabaseExplorer";
public Derived()
{
SerializationId = SerializationIdText;
}
}
Instead of looping twice, why not perform the functions of the second loop withint the first the first?
static void Main(string[] args)
{
List<Base> objects = new List<Base>();
List<string> serializationIds = new List<string>();
// SerializationIds initialized somehow
foreach (var serializationId in serializationIds)
{
switch(serializationId)
{
// Identify class
case Derived.SerializationIdText:
string serializationId = item.SerializationId;
// Do something with serializationId;
break;
}
}
}
You might be able to refactor out the code within the switch statement, too, so you could have something like
static void Main(string[] args)
{
List<Base> objects = new List<Base>();
List<string> serializationIds = new List<string>();
// SerializationIds initialized somehow
foreach (var serializationId in serializationIds)
{
string serializationId = item.SerializationId;
// Do something with serializationId;
}
}
I have an object which I would like to monitor in case its data changes. However I am not allowed to add additional events or interfaces like INotifyPropertyChanged to the object, so I need to purely watch it from the outside and see if it has changed in character and the go through all it's properties to identify what has changed.
So I basically need a FileSystemWatcher, but for an object.
Does C# offer any functionality I am looking for here?
You'll have to brute-force it and do something like capturing the state of the object and then look for differences when you need to detect changes (either through periodic polling or at specific points where you need to know the diffs).
This, I believe, is what a number of systems that monitor for changes in data model objects do (e.g. RavenDB).
I made a quick and dirty console app that roughly does what you are wanting. It should be enough to give you an idea but will need a whole lotta work if you want to use it in production code. :)
class Program
{
static void Main(string[] args)
{
DemoClass demo = new DemoClass { IntValue = 1, StringValue = "asdf" };
var watcher = new DemoClassWatcher();
watcher.Capture(demo);
demo.StringValue = "1234";
var results = watcher.Compare(demo); // results = "StringValue"
demo.IntValue = 1234;
results = watcher.Compare(demo); // results = "StringValue", "IntValue"
watcher.Capture(demo);
results = watcher.Compare(demo); // results = empty
}
}
public class DemoClass
{
public string StringValue { get; set; }
public int IntValue { get; set; }
}
public class DemoClassWatcher
{
private DemoClass lastRecorded = null;
public void Capture(DemoClass objectToWatch)
{
lastRecorded = new DemoClass()
{
IntValue = objectToWatch.IntValue,
StringValue = objectToWatch.StringValue
};
}
public List<string> Compare(DemoClass currentObject)
{
var changes = new List<string>();
var props = typeof(DemoClass).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var propertyInfo in props)
{
var currentVal = propertyInfo.GetValue(currentObject);
var prevVal = propertyInfo.GetValue(lastRecorded);
if (currentVal is IComparable)
{
if ((currentVal as IComparable).CompareTo(prevVal) != 0)
changes.Add(propertyInfo.Name);
continue;
}
throw new NotSupportedException("Properties must support IComparable until someone fixes me up");
}
return changes;
}
}
You can't listen for events that are not there, but you can poll the states and compare them to their previous state.
Pseudocode:
///initial config:
yourObject = getAReferenceToTheObject();
previousState = new ObjectClass(yourObject);
///somewhere in a thread/loop
if (previousState.SomeProperty!= yourObject.SomeProperty){
//state changed for SomeProperty on yourObject
}
//TODO: check other properties
previousState = new ObjectClass(yourObject); //implement copy constructor
I'm doing an application where I have the following scenario:
I have several rules (business classes)
where they all return the client code. They are separate classes that will look for the code trial and error, if find the client code returns it and so on.
How can I use a rule without using a bunch of IFs or threaded IFs in the class that calls the others that contains the specific business rules?
For the specific classes, I used the design pattern strategy.
EX: Main Class
public abstract class Geral
{
public abstract string retornaCodigo(Arquivo cliente)
{
var codigo = ""; // logica
return codigo;
}
}
public class derivada1 : Geral
{
public override string retornaCodigo(Arquivo cliente)
{
var codigo = ""; // logica
return codigo;
}
}
public class derivada2 : Geral
{
public override string retornaCodigo(Arquivo cliente)
{
var codigo = ""; // logica 2
return codigo;
}
}
public class derivada3 : Geral
{
public override string retornaCodigo(Arquivo cliente)
{
var codigo = ""; // logica 3
return codigo ;
}
}
public class Negocio
{
public string Codigo()
{
var arquivo = new Arquivo();
var derivada1 = new derivada1().retornaCodigo(arquivo);
var derivada2 = new derivada2().retornaCodigo(arquivo);
var derivada3 = new derivada3().retornaCodigo(arquivo);
if (derivada1.Equals(null))
return derivada1;
if (derivada2.Equals(null))
return derivada2;
if (derivada3.Equals(null))
return derivada3;
return "";
}
}
what I wanted and that I did not have to use Ifs in the Business class for validation whether or not I found the code where it can fall under any condition gave example of 3 classes plus I have more than 15 conditions and can increase, case would be many Ifs.
Let's organize all derivada into a collection, say, array and then query the collection with a help of Linq
public string Codigo() {
var arquivo = new Arquivo();
Geral[] derivadas = new [] {
new derivada1(),
new derivada2(),
new derivada3();
};
//TODO: check the the condition: I guessed that you want to return first meanful codigo
foreach (var codigo in derivadas.Select(geral => geral.retornaCodigo(arquivo)))
if (!string.IsNullOrEmpty(codigo))
return codigo;
return "";
}
If you have a lot of derivada you can try using Reflection in order to create a collection:
using System.Reflection;
...
private static Geral[] s_Derivadas = AppDomain
.CurrentDomain
.GetAssemblies() // scan assemblies
.SelectMany(asm => asm.GetTypes()) // types within them
.Where(t => !t.IsAbstract) // type is not abstract
.Where(t => typeof(Geral).IsAssignableFrom(t)) // type derived from Geral
.Where(t => t.GetConstructor(Type.EmptyTypes) != null) // has default constructor
.Select(t => Activator.CreateInstance(t) as Geral) // create type's instance
.ToArray(); // materialized as array
then
public string Codigo() {
var arquivo = new Arquivo();
foreach (var codigo in s_Derivadas.Select(geral => geral.retornaCodigo(arquivo)))
if (!string.IsNullOrEmpty(codigo))
return codigo;
return "";
}
You could create a list of derivada's and then iterate over it
and if any given derivada1 equals None, you simply return it, otherwise you just continue the 'for loop'
I could write up a snippet if this doesn't make sense to you. lmk!
This would be simple with Linq:
public class Negocio
{
public string Codigo()
{
var arquivo = new Arquivo();
var derivadaList = new List<Geral>() {
new derivada1(),
new derivada2(),
new derivada3(),
};
return derivadaList.FirstOrDefault(d => d.retornaCodigo(arquivo) == null)?.retornaCodigo(arquivo) ?? "";
}
}
You can add as many Geral derived classes to the derivadaList as you want and the code will continue to function as designed.
What is happening here is that FirstOrDefault will run the Lamda expression on every element returning the first one that equals null (although I'm not sure this is what you want, it matches your example code). Since it returns a Geral object, you need to call retornaCodigo on it only if it is not null. If it is null, just return an empty string.
Another way to write this would be:
public class Negocio
{
public string Codigo()
{
var arquivo = new Arquivo();
var derivadaList = new List<Geral>() {
new derivada1(),
new derivada2(),
new derivada3(),
};
foreach (var derivada in derivadaList)
{
var result = derivada.retornaCodigo(arquivo);
if (result == null)
return result;
}
return "";
}
}
You can also use a list of derived classes and call them in Loop
public string Codigo()
{
var arquivo = new Arquivo();
List<Geral> gerals=new List<Geral>();
gerals.Add(new derivada1());
gerals.Add(new derivada2());
........
...........
foreach(Geral g in gerals)
{
var val=g.retornaCodigo(arquivo);
if(val!=null)
return val;
}
return "";
}
This is a sample implementation, However you are not using strategy correctly
A better approach will be constructor injection,
public string Codigo(Geral implementar)
{
var val=geral.retornaCodigo(arquivo);
return "";
}
Then instantiate only with the chosen strategy.
Otherwise if you want to chain multiple validations, then use CHain of responsibility pattern.