How I can to avoid IoC locator in next case? - c#

In brief: I want resolve interface by prop in entity.
I have self hosted wcf and use ninject for DI.
My working code for example:
//program.cs
...
private static StandardKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<IDbConnectionFactory>().ToMethod(c =>
new OrmLiteConnectionFactory(
conString,
SqlServerDialect.Provider))
.InSingletonScope();
kernel.Bind<IControllerProccessor>().To<ControllerProccessor>()
.WhenInjectedInto<HelloWorldService>().WithConstructorArgument(kernel);
kernel.Bind<IControllerProccessor>().To<Vendor1Proccessor>()
.Named("vendor1");
kernel.Bind<IControllerProccessor>().To<Vendor2Proccessor>()
.Named("vendor2");
return kernel;
}
...
//IControllerProccessor.cs
public interface IControllerProccessor
{
SimpleController Ctr { get; set; }
bool sendMsg(string msg);
}
//Vendor1Proccessor.cs
public class Vendor1Proccessor : IControllerProccessor
{
public SimpleController Ctr {get; set;}
public bool sendMsg(string msg)
{
//specific to vendor code, for example calls to vendor1 SDK
Console.WriteLine("Controller id: {0} vendor:{1} recivied msg: {2}",
Ctr.Id,
"Vendor1Class",
msg);
return true;
}
}
//Vendor2Proccessor.cs
public class Vendor2Proccessor : IControllerProccessor
{
public SimpleController Ctr { get; set; }
public bool sendMsg(string msg)
{
//specific to vendor code, for example calls to vendor1 SDK
Console.WriteLine("Controller id: {0} vendor:{1} recivied msg: {2}",
Ctr.Id,
"Vendor2Class",
msg);
return true;
}
}
//ControllerProccessor.cs
public class ControllerProccessor : IControllerProccessor
{
public SimpleController Ctr {get; set;}
private readonly IKernel kernel;
public ControllerProccessor(IKernel _kernel)
{
kernel = _kernel;
}
public bool sendMsg(string msg)
{
var param = new Ninject.Parameters.PropertyValue("Ctr", Ctr);
return kernel.Get<IControllerProccessor>(Ctr.Vendor, param).sendMsg(msg);
}
}
//HelloWorldService.cs
public class HelloWorldService : IHelloWorldService
{
private readonly IDbConnectionFactory dbFactory;
private readonly IControllerProccessor ctrProccessor;
public HelloWorldService(IDbConnectionFactory _dbFactory, IControllerProccessor _ctrProccesor)
{
dbFactory = _dbFactory;
ctrProccessor = _ctrProccesor;
}
public bool sendMsgToAllControllers(string msg)
{
var db = dbFactory.Open();
var controllers = db.Select<SimpleController>();
foreach(var ctr in controllers)
{
ctrProccessor.Ctr = ctr;
ctrProccessor.sendMsg(msg);
}
db.Close();
return true;
}
}
//SimpleController.cs
[DataContract]
[Alias("SimpleController")]
public class SimpleController
{
[AutoIncrement]
[DataMember]
public int? Id { get; set; }
[DataMember]
public string Vendor { get; set; }
}
When I call sendMsgToAllControllers("TEST_MESSAGE") console output:
Controller id: 2 vendor:Vendor1Class recivied msg: TEST MESSAGE
Controller id: 3 vendor:Vendor2Class recivied msg: TEST MESSAGE
Controller id: 4 vendor:Vendor2Class recivied msg: TEST MESSAGE
How I can refactor above implementation so that it was in DI style, and dont use IoC locator anti-pattern (or in my case this is not anti-pattern) ?
In future I will move implementations (vendor1, vendor2, etc..) in separate assembly and do runtime binding. (Here I want to plugin system)
I also would appreciate any suggestions to improve my code. Very thanks.
Modification of implementation
After thinking process I came to the following:
I remove ControllerProccessor class instead I create ControllerProcessorFactory:
public class ControllerProcessorFactory : IControllerProcessorFactory
{
private readonly IResolutionRoot resolutionRoot;
public ControllerProcessorFactory(IResolutionRoot _resolutionRoot)
{
resolutionRoot = _resolutionRoot;
}
public IControllerProcessor Create(SimpleController ctr)
{
IControllerProcessor processor = resolutionRoot.Get<IControllerProcessor>(ctr.Vendor);
processor.Ctr = ctr;
return processor;
}
}
In Bindings:
kernel.Bind<IControllerProcessorFactory>().To<ControllerProcessorFactory>();
kernel.Bind<IControllerProcessor>().To<Vendor1Processor>()
.Named("vendor1");
kernel.Bind<IControllerProcessor>().To<Vendor2Processor>()
.Named("vendor2");
Usage (wcf class):
public class HelloWorldService : IHelloWorldService
{
private readonly IDbConnectionFactory dbFactory;
private readonly IControllerProcessorFactory ctrProcessorFactory;
public HelloWorldService(IDbConnectionFactory _dbFactory, IControllerProcessorFactory _ctrProcFactory)
{
dbFactory = _dbFactory;
ctrProcessorFactory = _ctrProcFactory;
}
public bool sendMsgToAllControllers(string msg)
{
var db = dbFactory.Open();
var controllers = db.Select<SimpleController>();
foreach(var ctr in controllers)
{
var ctrProcessor = ctrProcessorFactory.Create(ctr);
ctrProcessor.sendMsg(msg);
}
db.Close();
return true;
}
}

kernel.Get<IControllerProccessor>(Ctr.Vendor, param) is service locator,
but then again that doesn't always mean "it" is a problem. If it's easily interchangable, then it's not a big deal (well at least that's the opinion of some). Easily interchangeable? Create a specific factory interface whose only responsibility is to return all the processors.
The implementation then would consist of exactly return kernel.Get<IControllerProccessor>(Ctr.Vendor, param);. As long as the implementation is part of the composition root this specfici dependency on ninject is ok.
Shorter Alternative
Now, to be honest, your design looks superfluosly complicated to me, but then again, i don't know all the details. So for now i'm just using the name parameter, but you can easily add parameters (almost) as you like, it'll still work:
Just inject a Func<string, IControllerProcessor> instead of the kernel:
public ControllerProccessor(
Func<string,IControllerProcessor>> controllerProcessorFactory)
You can then specfiy a binding as follows:
private static IControllerProcessor CreateSpecificControllerProcessor(
IResolutionRoot resolutionRoot, string vendorName)
{
return resolutionRoot.Get<IControllerProcessor>(vendorName);
}
Bind<Func<IControllerProcessor>()
.ToConstant(vendorName => CreateSpecficiControllerProcessor(this.Kernel, vendorName));
Instead of specifying the Binding for the Func it might be possible to use Ninject.Extensions.Factory. Note however, that when you use this extension it won't be possible to Bind any Func manually anymore (the binding will be overriden by the extensions generation mechanism).

Look at Dynamic module loading in their documentation.
i.e.
kernel.Load("*.dll");
But make sure you do this at startup so you don't overwhelm your system at runtime.
As far as your pattern, I would recommend using the GetAll() method on the kernel as that will give you more flexibility and control
IEnumerable<IControllerProccessor> processors = kernel.GetAll<IControllerProccessor>();
foreach(var processor in processors)
processor.sendMsg(....);

Related

How to make the ActivatorUtilities.CreateInstance method use a different constructor?

Is there a way the tell the ActivatorUtilities.CreateInstance<T>(IServiceProvider serviceProvider); method to try to use other constructors if the first one can't be constructed?
I have a class with multiple constructors:
public ViewModelB(SomeDependency someDependency): this one only takes SomeDependency which is registered in a DI container
public ViewModelB(SomeDependency someDependency, GetUserRequest request): this one takes SomeDependency which is registered in a DI container and a GetUserRequest which has to be passed in manually
And I'm trying to activate them and resolve dependencies like so:
IServiceProvider serviceProvider; //this gets passed from somewhere
Guid userId; //this gets passed manually by the caller
//works
var instanceAWithoutParams = ActivatorUtilities.CreateInstance<ViewModelA>(serviceProvider);
//works
var instanceAWithParams = ActivatorUtilities.CreateInstance<ViewModelA>(serviceProvider, new[] { new GetUserRequest { UserId = userId } });
//does NOT work, it tries to use the first constructor and fails
var instanceBWithoutParams = ActivatorUtilities.CreateInstance<ViewModelB>(serviceProvider);
//works
var instanceBWithParams = ActivatorUtilities.CreateInstance<ViewModelB>(serviceProvider,, new[] { new GetUserRequest { UserId = userId } });
The activation of instanceBWithoutParams fails because it can't resolve the request parameter. It tries to use the first constructor and doesn't check other ones when the activation fails.
Here's what the services look like, they're the same with one difference: the order of the constructors.
public class ViewModelA
{
private readonly SomeDependency _someDependency;
private readonly GetUserRequest? _request;
public ViewModelA(SomeDependency someDependency)
{
_someDependency = someDependency;
}
public ViewModelA(SomeDependency someDependency, GetUserRequest request)
{
_someDependency = someDependency;
_request = request;
}
}
public class ViewModelB
{
private readonly SomeDependency _someDependency;
private readonly GetUserRequest? _request;
public ViewModelB(SomeDependency someDependency, GetUserRequest request)
{
_someDependency = someDependency;
_request = request;
}
public ViewModelB(SomeDependency someDependency)
{
_someDependency = someDependency;
}
}
public class GetUserRequest
{
public Guid UserId { get; set; }
}
Thanks.
I struggled with the same issue. Eventually I came up with this solution:
I would use something like a factory which is able to construct ServiceB by calling a method.
For example:
var serviceBFactory = ActivatorUtilities.CreateInstance<ServiceBFactory>(serviceProvider);
var instanceBWithoutParams = serviceBFactory.CreateServiceB();
var instanceBWithParams = serviceBFactory.CreateServiceB(new Request());
This way you keep you DI clean. But this means that the ServiceBFactory need to know which services need to be injected in a ServiceB. (so that will be a tight coupling) They come as a package.
I've chosen to re-design the view models instead of trying to pass optional parameters next to services from DI (thanks to Steven for the helpful articles: 1 and 2).
There also seems to be no way of making the ActivatorUtilities.CreateInstance<T>(IServiceProvider serviceProvider); method try other constructors after one fails, so here's what my edited solution looks like.
I've moved the initialization of the optional parameter out of the constructor, that way I only have one constructor that only takes injectables. The parameter is then passed separately via the TakeParameter method. The only downside I can think of is that the parameter can no longer be readonly and I can live with that.
My custom activator utility:
public interface IAcceptParameter<T>
{
void TakeParameter(T parameter);
}
public static class CustomActivator
{
public static T CreateInstance<T>()
{
return ActivatorUtilities.CreateInstance<T>(_serviceProvider);
}
public static T CreateInstanceWithParam<T, K>(K parameter) where T : IAcceptParameter<K>
{
var instance = ActivatorUtilities.CreateInstance<T>(_serviceProvider);
instance.TakeParameter(parameter);
return instance;
}
}
Changed view model
public class SomeViewModel : IAcceptParameter<Guid>
{
private readonly SomeDependency _someDependency;
private Guid? _userId;
public SomeViewModel(SomeDependency someDependency)
{
_someDependency = someDependency;
}
public void TakeParameter(Guid parameter){
_userId = parameter;
}
}
How I use it
var instanceWithoutParam = CustomActivator.CreateInstance<SomeViewModel>(serviceProvider);
Guid userId;
var instanceWithParam = CustomActivator.CreateInstanceWithParam<SomeViewModel, Guid>(serviceProvider, userId);
Let say you have a class like this:
public class a
{
public string p { get; set; }
public a()
{
p = "default constructor";
}
public a(string pv)
{
p = pv;
}
}
You can use .GetConstructor method to use a specific constructor:
public class Program
{
static void Main(string[] args)
{
var c = typeof(a).GetConstructor(new Type[] { typeof(string) });
if (c != null)
{
var myA = (a)c.Invoke(new object[] { "new value" });
Console.WriteLine($"Value of p is {myA.p}");
}
}
}

dependency injection based on user input

Consider the code snippet (I used the strategy Pattern in the example) :
abstract class SortStrategy
{
public abstract void Sort(ArrayList list);
}
class QuickSort : SortStrategy
{
public override void Sort(ArrayList list)
{
//...
}
}
class ShellSort : SortStrategy
{
public override void Sort(ArrayList list)
{
// ....
}
}
and in Context :
class SortedList
{
private ArrayList list = new ArrayList();
private SortStrategy sortstrategy;
public void SetSortStrategy(SortStrategy sortstrategy)
{
this.sortstrategy = sortstrategy;
}
public void Add(string name)
{
list.Add(name);
}
public void Sort()
{
sortstrategy.Sort(list);
}
}
My question is that the end user through the UI and by selecting an option says to use the method for example QuickSort to sort, but what should I do, how to set SetSortStrategy (or how to dependency injection in this case)
I suggest using factory pattern with dependency injection:
public enum StrategyType
{
A,
B,
C
}
public interface IStrategyFactory {
IStrategy Create();
}
public class BasedOnUserSelStrategyFactory {
public IStrategy Create() {
StrategyType type = ReadUserSelectionFromFile(); // or any place stored
switch (type) {
case StrategyType.A:
return di.Resolve<AStrategy>(); // resolve using di container
case StrategyType.B:
return di.Resolve<BStrategy>(); // resolve using di container
case StrategyType.C:
return di.Resolve<CStrategy>(); // resolve using di container
default:
throw new ArgumentException("type");
}
}
}
Then, register factory in di:
di.Register<IStrategyFactory>().As<BasedOnUserSelStrategyFactory>();
Finally:
IStrategy s = di.Resolve<IStrategyFactory>().Create();
s.MyOperation();
The Castle.Windsor based DI of our MORYX-Framework allows users to configure a ModuleStrategy property in the config.
When a modules config looks like this:
public class ModuleConfig : ConfigBase
{
[DataMember, PluginStrategy(typeof(SortStrategy))]
[ModuleStrategy(typeof(SortStrategy))]
public string SortStrategy { get; set; }
}
The user can choose one of the found classes and every import of SortStragy is automatically filled with an instance. Using the graphic interface the user can select QuickSort and ShellSort, as well as any other implementation found at runtime from a drop-down box.
[Plugin(LifeCycle.Transient, typeof(SortStrategy))]
class QuickSort : SortStrategy
{
// ...
}
class SortedList
{
private ArrayList list = new ArrayList();
// injected with either QuickSort or ShellSort
public SortStrategy Sortstrategy { get; set; }
public void Add(string name)
{
list.Add(name);
}
public void Sort()
{
sortstrategy.Sort(list);
}
}
If you prefer to use the factory pattern, you can also declare a named factory. This can create any strategy registered as shown above.
[PluginFactory(typeof(INameBasedComponentSelector))]
public interface ISortStrategyFactory
{
SortStrategy Create(string name);
void Destroy(SortStrategy instance);
}
If you use Castle.Windsor, this is the code (Licensed under Apache2.0) we use to configure the override on all dependency declarations:
https://github.com/PHOENIXCONTACT/MORYX-Platform/blob/dev/src/Moryx.Container/LocalContainer/LocalRegistrator.cs#L34

Which design pattern to use when we have classes that does similar high level functionality but the returns different types in methods?

I have an existing C# console application that takes arguments and based on the arguments
creates an instance of markets (UK, US, MX..) using dependency injection.
Each market class does a 'string GetData()', 'string ProcessData()' and 'bool ExportData()'.
The application was initially created for one eCommerce vendor's markets. Now I am told to modify it for a different vendor that does a different process. The high-level flow remains the same.
'GetData' to fetch records from DB,
'ProcessData' for any transformation or the likes
'ExportData'.
The difference is Getdata() pulls records from DB and maps to an object. I am planning to use Petapoco. 'ProcessData' might return a similar class. 'Exportdata' currently does an API call but for the new vendor, I have to write to a file.
I was reading up on patterns I am totally confused. At first, I thought I needed abstract factory pattern and now I think the factory method is what I should be using but I am not sure if I am doing it right. Need some guidance/review here. A sample cs file I created from my understanding of factory pattern. This code is based on the headfirst code samples.
using System;
using System.Collections.Generic;
using StatusExport.Models;
namespace factorymethod
{
class Program
{
static void Main(string[] args)
{
ClientFactory factory = null;
Console.WriteLine("Enter client code:");
string clientCode= Console.ReadLine();
switch (clientCode.ToLower())
{
case "costco":
factory = new CostcoFactory("accountname", "taskname");
break;
//NEw vendor might be added
//case "walmart"
//factory = new WalmartFactory("taskname", "type");
//break
default:
break;
}
bool status = factory.ProcessData();
Console.ReadKey();
}
}
abstract class Client
{
public abstract string AccountName { get; }
public abstract string Task { get; set; }
//More properties might be added. Some may not even be used by some of the new vendors. For example, Costco Might need accountname and task. Tomorrow if walmart comes, they might not need these two or may need task and a new property 'type'
public abstract List<T> GetData<T>();
public abstract List<T> ProcessData<T>();
public abstract bool ExportData();
}
class CostcoClient : Client
{
public override string AccountName { get; }
public override string Task { get; set; }
public CostcoClient(string accountName, string task)
{
AccountName = accountName;
Task = task;
}
public override List<DBRecord> GetData<DBRecord>() //DBRecord class is specific to Costco.
{
List<DBRecord> dbresult = new List<DBRecord>();
//dbresult = db return data mapped to an object DBRecord using petapoco. Another vendor might have a different class to which DB records are mapped. So the return type can be generic
return asn;
}
public override List<T> ProcessData<T>()
{
throw new NotImplementedException(); //Any data transformation or business logic. Return type might be DBRecord or a new class altogether
}
public override bool ExportData()
{
throw new NotImplementedException();//Call API or write data to file and if success send true else false
}
}
abstract class ClientFactory
{
public abstract bool ProcessData();
}
class CostcoFactory : ClientFactory
{
public string AccountName { get; }
public string Task { get; set; }
public CostcoFactory(string accountname, string task)
{
AccountName = accountname;
Task = task;
}
public override bool ProcessData()
{
CostcoClient gc = new CostcoClient(AccountName, Task);
var result = gc.GetData<DBRecord>();
return true;
}
}
}
Do you think this is the right design approach?
I also want to keep the console project independent of vendor project. So maybe 'StatusExport.Program' for the console application. DLL projects StatusExport.Common to hold the interface and abstract classes' and 'StatusExport.Client(ex:StatusExport.Costco)' for each vendor stuff.
You can create BaseClient class that will contains a basic group of properties, and if you need to add something new - just inherit it. You did right, but i think it's better to change public modifier to protected in your properties AccountName and Task, to give access to them only from child classes.
Actually, you can create a BaseClientModels (request/response) for each method if you are not sure that returning type List will be always actual.
Example:
public abstract class BaseClient
{
#region Properties : Protected
protected abstract string AccountName { get; }
protected abstract string Task { get; set; }
#endregion
#region Methods : Public
public abstract BaseGetDataResponseModel GetData(BaseGetDataRequestModel model);
public abstract BaseProcessDataResponseModel ProcessData(BaseProcessDataRequestModel model);
public abstract BaseExportDataResponseModel ExportData(BaseExportDataRequestModel model);
#endregion
}
public class BaseGetDataResponseModel { }
public class BaseGetDataRequestModel { }
public class BaseProcessDataResponseModel { }
public class BaseProcessDataRequestModel { }
public class BaseExportDataResponseModel { }
public class BaseExportDataRequestModel { }
Then let's look on your class CostcoClient and how it can looks like:
public class CostcoClient : BaseClient
{
#region Properties : Protected
protected override string AccountName { get; }
protected override string Task { get; set; }
protected virtual IDataReader<BaseGetDataRequestModel, BaseGetDataResponseModel> DataReader { get; }
protected virtual IDataProcessor<CostcoClientProcessDataRequestModel, CostcoClientProcessDataResponseModel> DataProcessor { get; }
protected virtual IExportDataHandler<CostcoClientExportDataRequestModel, CostcoClientExportDataResponseModel> ExportDataHandler { get; }
#endregion
#region Constructors
public CostcoClient(string accountName, string task)
{
//set DataReader, DataProcessor, ExportDataHandler
AccountName = accountName;
Task = task;
}
#endregion
#region Methods : Public
public override BaseGetDataResponseModel GetData(BaseGetDataRequestModel model)
{
if (model is CostcoClientGetDataRequestModel clientGetDataRequestModel)
{
return DataReader.ReadData(clientGetDataRequestModel);
}
return null; //wrong type has passed
}
public override BaseProcessDataResponseModel ProcessData(BaseProcessDataRequestModel model)
{
if (model is CostcoClientProcessDataRequestModel clientProcessDataRequestModel)
{
return DataProcessor.ProcessData(clientProcessDataRequestModel);
}
return null;
}
public override BaseExportDataResponseModel ExportData(BaseExportDataRequestModel model)
{
if (model is CostcoClientExportDataRequestModel clientExportDataRequestModel)
{
return ExportDataHandler.Handle(clientExportDataRequestModel);
}
return null;
}
#endregion
}
public class CostcoClientGetDataRequestModel : BaseGetDataRequestModel { }
public class CostcoClientGetDataResponseModel : BaseGetDataResponseModel { }
public class CostcoClientProcessDataRequestModel : BaseProcessDataRequestModel { }
public class CostcoClientProcessDataResponseModel : BaseProcessDataResponseModel { }
public class CostcoClientExportDataRequestModel : BaseExportDataRequestModel { }
public class CostcoClientExportDataResponseModel : BaseExportDataResponseModel { }
public interface IDataReader<TIn, TOut>
{
public TOut ReadData(TIn model);
}
public interface IDataProcessor<TIn, TOut>
{
public TOut ProcessData(TIn model);
}
public interface IExportDataHandler<TIn, TOut>
{
public TOut Handle(TIn model);
}
public class CostcoClientDataReader : IDataReader<CostcoClientGetDataRequestModel, CostcoClientGetDataResponseModel>
{
public CostcoClientGetDataResponseModel ReadData(CostcoClientGetDataRequestModel model)
{
throw new NotImplementedException();
}
}
//and so on
You have to implement IDataReader, IDataProcessor, IExportDataHandler, make your logic and call it from GetData, ProcessData, ExportData methods, as an example, and get instances via dependency injection.
Then, we can change your factory to this:
public interface IClientFactory
{
BaseClient GetClientService(ClientServicesEnum value);
}
public class BaseClientFactory : IClientFactory
{
#region Propertied : Protected
protected virtual IEnumerable<BaseClient> Services { get; }
protected string AccountName { get; }
protected string Task { get; set; }
#endregion
#region Constructors
public BaseClientFactory(IEnumerable<BaseClient> services, string accountname, string task)
{
Services = services;
AccountName = accountname;
Task = task;
}
#endregion
public BaseClient GetClientService(ClientServicesEnum value)
=> Services.First(x => x.GetType().Equals(GetClientServiceByCode()[value]));
private Dictionary<ClientServicesEnum, Type> GetClientServiceByCode()
=> new Dictionary<ClientServicesEnum, Type>()
{
{ ClientServicesEnum.CostcoClient, typeof(CostcoClient) }
};
}
public enum ClientServicesEnum
{
CostcoClient = 1,
Another2 = 2,
Another3 = 3
}
Where
protected virtual IEnumerable<BaseClient> Services { get; }
you can get via DI too, and then get correct ServiceHandler by enum.
And your main function to call all this:
switch (clientCode)
{
case 1:
baseClient = ClientFactory.GetClientService(ClientServicesEnum.CostcoClient);
break;
case 2:
baseClient = ClientFactory.GetClientService(ClientServicesEnum.Another2);
break;
default:
break;
}
bool status = baseClient.ProcessData(null); //your model
The main thing is - you can use more than one pattern, for example one from Creational patterns, and one from Structural.
If i need some help in code architecture i use this:
https://refactoring.guru/
I think, using this example you can remove properties AccountName and Task, because of request models in methods.

Inherit in generic classes C#

My brain is gonna to explode. :) So I would like to get help from you.
Please, think about my question like about just programmer puzzle. (Actually. perhaps it is very easy question for you, but not for me.)
It is needed to create array of objects. For example List where T is class. (I will describe Class T below). Also it is needed create “container” that will contain this array and some methods for work with this array. For example Add(), Remove(int IndexToRemove).
Class T must have field "Container", this way each elements of our array would be able to know where is it contained and has access its container's fields and methods. Notice, that in this case Class T should have type parameter. Indeed, it is not known beforehand which container's type is used.
Let us denote this class container as A and class element (class T) as AUnit.
Code:
class Program
{
static void Main(string[] args)
{
A a = new A();
a.Add();
a.Units[0].SomeField +=100;
Console.ReadKey();
}
}
class A
{
public List<AUnit> Units;
public A()//ctor
{
Units = new List<AUnit>();
}
public void Add()
{
this.Units.Add(new AUnit(this));
}
}
class AUnit
{
public int SomeField;
public A Container;
public string Name { get; private set; }
public AUnit(A container)
{
this.SomeField = 43;
this.Container = container;
this.Name = "Default";
}
}
Public fields should be protected or private of course, but let think about this later.
You can ask “why we create public A Container field in AUnit”? We create field public string Name{get;private set;} (actually property but nevermind). And also we would like to be able to change value of this field for example method [Class AUnit] public bool Rename(string newName)();. The main idea of this method is changing Name field only that case if no one element in array (public List Units; ) has the same name like newName. But to achieve this, Rename method has to have access to all names that is currently used. And that is why we need Container field.
Code of extended version AUnit
class AUnit
{
public int SomeField;
public A Container;
public string Name { get; private set; }
public AUnit(A container)
{
this.SomeField = 43;
this.Container = container;
this.Name = "Default";
}
public bool Rename(String newName)
{
Boolean res = true;
foreach (AUnit unt in this.Container.Units)
{
if (unt.Name == newName)
{
res = false;
break;
}
}
if (res) this.Name = String.Copy(newName);
return res;
}
}
Ok. If you still read it let's continue. Now we need to create Class B and class BUnit which will be very similar like Class A and Class Aunit. And finally the main question of this puzzle is HOW WE CAN DO IT? Of course, I can CopyPaste and bit modify A and AUnit and create this code.
class B
{
public List<BUnit> Units; //Only Type Changing
public B()//ctor Name changing...
{
Units = new List<BUnit>();//Only Type Changing
}
public void Add()
{
this.Units.Add(new BUnit(this));//Only Type Changing
}
}
class BUnit
{
public int SomeField;
public B Container;//Only Type Changing
public string Name { get; private set; }
public A a; //NEW FIELD IS ADDED (just one)
public BUnit(B container) //Ctor Name and arguments type changing
{
this.SomeField = 43;
this.Container = container;
this.Name = "Default";
this.a=new A(); //New ROW (just one)
}
public bool Rename(String newName)
{
Boolean res = true;
foreach (BUnit unt in this.Container.Units) //Only Type Changing
{
if (unt.Name == newName)
{
res = false;
break;
}
}
if (res) this.Name = String.Copy(newName);
return res;
}
}
And I can to use this classes this way.
static void Main(string[] args)
{
B b = new B();
b.Add();
b.Units[0].a.Add();
b.Units[0].a.Units[0].SomeField += 100;
bool res= b.Units[0].a.Units[0].Rename("1");
res = b.Units[0].a.Units[0].Rename("1");
Console.ReadKey();
}
This construction is can be used to create “non-homogeneous trees”.
Help, I need somebody help, just no anybody…. [The Beatles]
I created B and BUnit using CopyPaste.
But how it can be done using “macro-definitions” or “Generic”, inherit or anything else in elegant style? (C# language)
I think that there is no reason to describe all my unsuccessful attempts and subquestions. Already topic is too long. : )
Thanks a lot if you still read it and understand what I would like to ask.
You need to implement a base type, lets call it UnitBase, with all common functionality. I'd structure your code the following way:
Create an interface for your container, this way you can change implementation to more performant solutions without modifying the elements you will be adding to the container.
public interface IContainer
{
Q Add<Q>() where Q : UnitBase, new();
IEnumerable<UnitBase> Units { get; }
}
Following the idea stated in 1, why not make the search logic belong to the container? It makes much more sense, as it will mostly depend on how the container is implemented:
public interface IContainer
{
Q Add<Q>() where Q : UnitBase, new();
IEnumerable<UnitBase> Units { get; }
bool Contains(string name);
}
A specific implementation of IContainer could be the following:
public class Container : IContainer
{
public Container()
{
list = new List<UnitBase>();
}
private List<UnitBase> list;
public Q Add<Q>() where Q: UnitBase, new()
{
var newItem = Activator.CreateInstance<Q>();
newItem.SetContainer(this);
list.Add(newItem);
return newItem;
}
public IEnumerable<UnitBase> Units => list.Select(i => i);
public bool Contains(string name) =>
Units.Any(unit => unit.Name == name);
}
Create a base class for your AUnit and BUnit types condensing all common functionality:
public abstract class UnitBase
{
protected UnitBase()
{
}
public IContainer Container { get; private set; }
public int SomeField;
public string Name { get; private set; }
public void SetContainer(IContainer container)
{
Container = container;
}
public bool Rename(String newName)
{
if (Container.Contains(newName))
return false;
this.Name = newName; //No need to use String.Copy
return true;
}
}
Implement your concrete types:
public class BUnit : UnitBase
{
public int SpecificBProperty { get; private set; }
public BUnit()
{
}
}
Shortcomings of this approach? Well, the container must be of type <UnitBase>, I've removed the generic type because it really wasn't doing much in this particular case as it would be invariant in the generic type.
Also, keep in mind that nothing in the type system avoids the following:
myContainer.Add<BUnit>();
myContainer.Add<AUnit>();
If having two different types in the same container is not an option then this whole set up kind of crumbles down. This issue was present in the previous solution too so its not something new, I simply forgot to point it out.
InBetween , I am very thankful to you for your advices. Actually I can't say that I understood your answer in full, but using your ideas I have done what I want.
Looks like my variant works well. However I would like to hear your (and everyone) opinions about code described below. The main goal of this structure is creating non-homogeneous trees. So could you estimate it from this side.
First of all. We need to create interfaces for both classes. We describe there all "cross-used" functions.
public interface IUnit<T>
{
string Name { get;}
void SetContainer(T t);
bool Rename(String newName);
}
public interface IContainer
{
bool IsNameBusy(String newName);
int Count { get; }
}
Next. Create Base for Unit Classes for future inheritance. We will use in this inheritors methods from Container Base so we need generic properties and IUnit interface.
class UnitBase<T> : IUnit<T> where T : IContainer
Unfortunately I don't know yet how to solve the problem with Constructor parameters. That is why I use method
SetContainer(T container).
Code:UnitBase
class UnitBase<T> : IUnit<T> where T : IContainer
{
protected T Container;
public string Name { get; private set; }
public UnitBase()
{
this.Name = "Default";
}
public void SetContainer(T container)
{
this.Container = container;
}
public bool Rename(String newName)
{
bool res = Container.IsNameBusy(newName);
if (!res) this.Name = String.Copy(newName);
return !res;
}
}
Next. Create ContainerBase
ContainerBase should:
1) has IContainer interface.
2)has information about what it will contain:
... where U : IUnit<C>, new()
3)and .... has information about what itself is. This information we need to pass as parameter to SetContainer() method.
Code ContainerBase:
class ContainerBase<U, C> : IContainer //U - Unit Class. C-Container Class
where U : IUnit<C>, new()
where C : ContainerBase<U, C>
{
protected List<U> Units;
public U this[int index] { get { return Units[index]; } }
public ContainerBase()//ctor
{
this.Units = new List<U>();
}
public void Add()
{
this.Units.Add(new U());
this.Units.Last().SetContainer(((C)this));//may be a bit strange but actualy this will have the same type as <C>
}
public bool IsNameBusy(String newName)
{
bool res = false;
foreach (var unt in this.Units)
{
if (unt.Name == newName)
{
res = true;
break;
}
}
return res;
}
public int Count { get { return this.Units.Count; } }
}
Cast ((TContainer)(this)) may be is a bit strange. But using ContainerBase we always should use NewInheritorContainer. So this cast is just do nothing…looks like...
Finally. This classes can be used like in this example.
class SheetContainer : ContainerBase<SheetUnit,SheetContainer> {public SheetContainer(){}}
class SheetUnit : UnitBase<SheetContainer>
{
public CellContainer Cells;
public PictureContainer Pictures;
public SheetUnit()
{
this.Cells = new CellContainer();
this.Pictures = new PictureContainer();
}
}
class CellContainer : ContainerBase<CellUnit, CellContainer> { public CellContainer() { } }
class CellUnit : UnitBase<CellContainer>
{
public string ValuePr;//Private Field
private const string ValuePrDefault = "Default";
public string Value//Property for Value
{
//All below are Just For Example.
get
{
return this.ValuePr;
}
set
{
if (String.IsNullOrEmpty(value))
{
this.ValuePr = ValuePrDefault;
}
else
{
this.ValuePr = String.Copy(value);
}
}
}
public CellUnit()
{
this.ValuePr = ValuePrDefault;
}
}
class PictureContainer : ContainerBase<PictureUnit, PictureContainer> { public PictureContainer() { } }
class PictureUnit : UnitBase<PictureContainer>
{
public int[,] Pixels{get;private set;}
public PictureUnit()
{
this.Pixels=new int[,]{{10,20,30},{11,12,13}};
}
public int GetSizeX()
{
return this.Pixels.GetLength(1);
}
public int GetSizeY()
{
return this.Pixels.GetLength(0);
}
public bool LoadFromFile(string path)
{
return false;
}
}
static void Main(string[] args)
{
SheetContainer Sheets = new SheetContainer();
Sheets.Add();
Sheets.Add();
Sheets.Add();
Sheets[0].Pictures.Add();
Sheets[1].Cells.Add();
Sheets[2].Pictures.Add();
Sheets[2].Cells.Add();
Sheets[2].Cells[0].Value = "FirstTest";
bool res= Sheets[0].Rename("First");//res=true
res=Sheets[2].Rename("First");//res =false
int res2 = Sheets.Count;
res2 = Sheets[2].Pictures[0].Pixels[1, 2];//13
res2 = Sheets[2].Pictures.Count;//1
res2 = Sheets[1].Pictures.Count;//0
res2 = Sheets[0].Pictures[0].GetSizeX();//3
Console.ReadKey();
}
Looks like it works like I want. But I didn’t test it full.
Let me say Thank you again, InBetween.

How to dynamically decorate a class?

I've got a simple decorator class like the following. Notice how my public methods all create a new instance of the to-be-decorated class, then forward the call to that instance.
The problem with this class is that whenever IMyService gets updated, I have to update this proxy class too.
public class MyProxyService : IMyService
{
readonly IMyServiceFactory _realServiceFactory;
public MyProxyService(IMyServiceFactory realServiceFactory)
{
_realServiceFactory = realServiceFactory;
}
private IMyService CreateRealService()
{
return _realServiceFactory.CreateRealService();
}
public int A()
{
return CreateRealService().A();
}
public int B(int b1)
{
return CreateRealService().B(int b1);
}
public int C(int c1, int c2)
{
return CreateRealService().C(c1,c2);
}
public int D(int d1, int d2, int d3)
{
return CreateRealService().D(d1,d2,d3);
}
public void E()
{
CreateRealService().E();
}
}
I've tried creating a dynamic version using Castle.DynamicProxy, without any luck so far.
Anyone know a good, simple way to dynamically create a decorator like this?
I was able to get this to work using DynamicProxy.ProxyGenerator's CreateInterfaceProxyWithTargetInterface(..) .
I first created a dynamic proxy factory. This returns a proxy object, for which each method will be intercepted by the provided IInterceptor:
public class MyDynamicallyDecoratedServiceClientFactory
{
readonly ProxyGenerator _proxyGenerator;
readonly IInterceptor _interceptor;
public MyServiceClientFactory(IInterceptor interceptor)
{
_interceptor = interceptor;
_proxyGenerator = new ProxyGenerator();
}
public IMyService Create()
{
IMyService proxy = _proxyGenerator.CreateInterfaceProxyWithTargetInterface<IMyService>(null, _interceptor);
return proxy;
}
}
I then implemented the interceptor. Upon each method call, this interceptor will be called, which will create a new IMyService from the provided IMyServiceFactory, and delegate the method call to that new instance.
public class MyServiceClientInterceptor : IInterceptor
{
readonly IMyServiceFactory _svcFactory;
public MyServiceClientInterceptor(IMyServiceFactory svcFactory)
{
_svcFactory = svcFactory;
}
public void Intercept(IInvocation invocation)
{
IMyService realService = _svcFactory.Create();
IChangeProxyTarget changeProxyTarget = invocation as IChangeProxyTarget;
changeProxyTarget.ChangeInvocationTarget(realService);
invocation.Proceed();
}
}
Finally, to make use of all this:
// Create a service factory (the to-be-decorated class)
IMyServiceFactory myRealServiceFactory = /* ... */;
// Create a factory that will create decorated services
MyServiceClientInterceptor interceptor =
new MyServiceClientInterceptor(myRealServiceFactory);
MyDynamicallyDecoratedServiceClientFactory svcFactory =
new MyDynamicallyDecoratedServiceClientFactory(interceptor);
// Create a service client
IMyService svc = svcFactory.Create();
// Use it!
svcProxy.A();

Categories