Generic Factory Method Casting Issue - c#

Trying to create a factory to return a generic interface (following this answer) but getting the error:
Can't implicitly convert IFinancialsSyncService<Vendor, QuickBooksVendor> to IFinancialsSyncService<TEntity, TQuickBooksEntity>. Anexplicit conversion exists, are you missing a cast?
public class QuickBooksEntityServiceFactory
{
public IFinancialsSyncService<TEntity, TQuickBooksEntity> Create<TEntity, TQuickBooksEntity>()
where TEntity : class, IEntity, IFinancials, new()
where TQuickBooksEntity : class, IQuickBooksEntity
{
if (typeof(TEntity) == typeof(QuickBooksVendor))
{
return new QuickbooksVendorService();
}
throw new InvalidOperationException();
}
}
The service confirms to the IFinancialsSyncService interface:
public class QuickbooksVendorService : IFinancialsSyncService<Vendor, QuickBooksVendor>
However, if I cast it explicitly, I get a Cast is redundant error along with the first error still.
return (IFinancialsSyncService<Vendor, QuickBooksVendor>)new QuickbooksVendorService();
So the error is confusing me. What am I doing wrong?
UPDATE
This is what I'm trying to simplify. There are several instances similar to this also that call other common methods of the interface.
switch (enumDataElement)
{
//Export jobs
case DataElement.Item:
var itemService = new QuickbooksItemService();
exportResult = itemService.UpdateMozzoEntityWithFinancialsId(session, response, EntityId, intUserId);
break;
case DataElement.Vendor:
var VendorService = new QuickbooksVendorService();
exportResult = UpdateMozzoEntityWithFinancialsId(new QuickbooksVendorService(),session, response, EntityId, intUserId);
break;
case DataElement.Bill:
var billService = new QuickbooksBillService();
exportResult = billService.UpdateMozzoEntityWithFinancialsId(session, response, intUserId);
break;
case DataElement.PurchaseOrder:
var qbPOService = new QuickbooksPurchaseOrderService();
exportResult = qbPOService.UpdateMozzoEntityWithFinancialsId(session, response, intUserId);
break;
case DataElement.SalesReceipt:
var salesReceiptService = new QuickbooksSalesReceiptService();
exportResult = salesReceiptService.UpdateStratusEntityWithFinancialsId(session, response, intUserId);
break;
}
And replace it with something like:
var qbEntityService = EntityServiceFactory.Create(enumDataElement);
What would this factory look like?

This has to do with Liskov's Substitution Principle. Imagine that your Generic type is instead a property of the interface:
public interface IFinancials { }
public interface IFinancialsSyncService
{
IFinancials Financials { get; set; }
}
Now we implement this interfaces:
public class Financials : IFinancials {}
public class FinancialsSyncService : IFinancialSyncService
{
public Financials Financials { get; set; }
}
This results in a compiler error:
Compilation error: 'Program.FinancialsSyncService' does not implement interface member 'Program.IFinancialsSyncService.Financials'. 'Program.FinancialsSyncService.Financials' cannot implement 'Program.IFinancialsSyncService.Financials' because it does not have the matching return type of 'Program.IFinancials'.
Both problems have the same issue. In my example, the interface states that the result is of type IFinancials but is a more specific derived type Financials and even though any valid value that is placed in the property fulfills the interface, it cannot be replaced with any value derived from IFinancials only types that derive from Financials.
So if your code looked like:
public interface IFinancialsSyncService<TEntity>
where TEntity : IEntity
{
TEntity Financials { get; set; }
}
and you create a class:
public class QuickbooksVendorService : IFinancialSyncService<Vendor>
{
public Vendor Financials { get; set; }
}
However, now QuickbooksVendorService is a IFinancialSyncService<Vendor> not a IFinancialSyncService<TEntity> because the property is the derived type. Even if you didn't have this specific property it still leads to the same problem that generic type is more specific than the interface.

use Factory method and Adapter pattern
[TestFixture]
public class Class1
{
[Test]
public void Go()
{
var qbItem = Export(1);
var qbVendor= Export(2);
var qbSales= Export(3);
}
public qbEntityService Export(int number)
{
var qb = Class1.Create(number);
return qb.UpdateMozzoEntityWithFinancialsId();
}
public static IEntityService Create(int enumDataElement)
{
switch (enumDataElement)
{
case 1:
return new QuickbooksItemService();
case 2:
return new QuickbooksVendorService();
case 3:
return new QuickbooksSalesReceiptServiceAdapter(new QuickbooksSalesReceiptService());
default:
throw new Exception();
}
}
}
public interface IEntityService
{
qbEntityService UpdateMozzoEntityWithFinancialsId();
}
public class qbEntityService
{
}
public class QuickbooksItemService : IEntityService
{
public qbEntityService UpdateMozzoEntityWithFinancialsId()
{
Console.WriteLine("I am QuickbooksItemService, performing UpdateMozzoEntityWithFinancialsId");
return new qbEntityService();
}
}
public class QuickbooksVendorService : IEntityService
{
public qbEntityService UpdateMozzoEntityWithFinancialsId()
{
Console.WriteLine("I am QuickbooksVendorService, performing UpdateMozzoEntityWithFinancialsId");
return new qbEntityService();
}
}
public class QuickbooksSalesReceiptService
{
public qbEntityService UpdateStratusEntityWithFinancialsId()
{
Console.WriteLine("I am QuickbooksSalesReceiptService, performing UpdateStratusEntityWithFinancialsId");
return new qbEntityService();
}
}
public class QuickbooksSalesReceiptServiceAdapter : IEntityService
{
private QuickbooksSalesReceiptService adaptee;
public QuickbooksSalesReceiptServiceAdapter(QuickbooksSalesReceiptService adaptee)
{
this.adaptee = adaptee;
}
public qbEntityService UpdateMozzoEntityWithFinancialsId()
{
return adaptee.UpdateStratusEntityWithFinancialsId();
}
}

Related

chain of responsibility and generics

I have a chain of responsibility that applies filters to a collection. I am trying to make a factory to build that chain of responsibility from a configuration. My concrete types for the chain arent generic but their abstraction are, and the genericity makes me struggle to put them in a collection for a mapping between config and correct chain node implementation.
Here is the implementation of the chain :
public interface IFilter<T> where T : IFilterable
{
IFilter<T> SetNext(IFilter<T> next);
IEnumerable<T> Filter(IEnumerable<T> data);
}
public class BaseFilter<T> : IFilter<T> where T : IFilterable
{
protected IFilter<T> Next { get; set; }
public IFilter<T> SetNext(IFilter<T> next)
{
Next = next;
return Next;
}
public virtual IEnumerable<T> Filter(IEnumerable<T> data)
{
return Next == null ? data : Next.Filter(data);
}
}
Here is an example of concrete implementation of the nodes of the chain :
public interface IFilterable {}
public interface ICanFly: IFilterable
{
bool CanFly { get; }
}
public interface ITransport : IFilterable
{
int Passengers { get; }
}
public class Duck : ICanFly
{
public bool CanFly => true;
}
public class Plane : ICanFly, ITransport
{
public bool CanFly => true;
public int Passengers => 5;
}
public class FlyerFilter : BaseFilter<ICanFly>
{
public override IEnumerable<ICanFly> Filter(IEnumerable<ICanFly> data)
{
return base.Filter(data.Where(x => x.CanFly));
}
}
public class SmallTransportFilter : BaseFilter<ITransport>
{
public override IEnumerable<ITransport> Filter(IEnumerable<ITransport> data)
{
return base.Filter(data.Where(x => x.Passengers < 8));
}
}
My problems start when I want to make a factory that map the configuration to my concrete types (FlyerFilter and SmallTransportFilter in my example)
public interface IFilterChainBuilder<T> where T : IFilterable
{
IFilter<T> GenerateFilterResponsabilityChain(IEnumerable<string> filtersParam);
}
public class FilterChainBuilder<T> : IFilterChainBuilder<T> where T : IFilterable
{
private readonly Dictionary<string, IFilter<T>> _paramToFiltersMap;
public FilterChainBuilder()
{
_paramToFiltersMap = new Dictionary<string, IFilter<T>>(StringComparer.OrdinalIgnoreCase)
{
{"Flyers", new FlyerFilter()}, // Compile error, cannot convert from FlyerFilter to IFilter<T>
{"SmallTransport", new SmallTransportFilter()} // Compile error, cannot convert from SmallTransportFilter to IFilter<T>
};
}
public IFilter<T> GenerateFilterResponsabilityChain(IEnumerable<string> filtersParam)
{
IFilter<T> filterResponsabilityChain = null;
foreach (var parameter in filtersParam)
if (_paramToFiltersMap.TryGetValue(parameter, out var filter))
{
if (filterResponsabilityChain == null)
filterResponsabilityChain = filter;
else
filterResponsabilityChain.SetNext(filter);
}
else
{
throw new ArgumentException(
$"config parameter {parameter} has no associated IFilter");
}
return filterResponsabilityChain ?? new BaseFilter<T>();
}
}
I can understand why it doesnt compile. Since FlyerFilter is a BaseFilter<ICanFly> (so a IFilter<ICanFly>), it would be bad if I declared a new FilterChainBuilder<PlaceholderType>. And actually since SmallTransportFilter inherit from a different T type, the only possible IFilterable implementation would have to implement both ITransport and ICanFly.
I tried to remove the generic T type entirely but the consummer of this chain of responsability relies on that IEnumerable<T> Filter(IEnumerable<T> data) signature and wants an enumeration of concrete types rather than IFilterable.
I am not sure how could I fix this problem, I am currently stuck here.
Pavel is correct - Your definition of IFilter makes the type parameter T invariant. Putting covariance/controvariance/invariance aside, the design itself is questionable. For example, FlyFilter works only against ICanFly instances, but there is no code filters the input down to ICanFly elements only - shouldn't that be the responsibility of FlyFilter as well? I would personally suggest you use type info in your filters directly, maybe something like below:
public interface IFilterable { }
public class CanFly : IFilterable { }
public class Duck : CanFly { }
public abstract class Transportation : CanFly
{
public abstract int Passengers { get; }
}
public class Plane : Transportation
{
public override int Passengers => 5;
}
public class FlyerFilter : BaseFilter<IFilterable>
{
public override IEnumerable<IFilterable> Filter(IEnumerable<IFilterable> data)
{
return base.Filter(data.Where(x => x is CanFly));
}
}
public class SmallTransportFilter : BaseFilter<IFilterable>
{
public override IEnumerable<IFilterable> Filter(IEnumerable<IFilterable> data)
{
return base.Filter(data.Where(x => x is Transportation t && t.Passengers < 8));
}
}

How to return interface using generic in C#

I am new in C# Generic concept and I would like to return interface implemented class using generic concept. Below is my example which is currently implemented without generic:
1) Factory Class which return interface and this class has two overload method which accept different data model:
public class Factory
{
public ICommon Init(DBInfoData dbInfoData)
{
return new ClassA(dbInfoData);
}
public ICommon Init(WebInfoData webInfoData)
{
return new ClassB(webInfoData);
}
}
2) Interface and interface implemented two class as below:
//=== Common Interface
public interface ICommon
{
void MethodA();
void MethodB();
}
//=== Internal access only ClassA
internal class ClassA : ICommon
{
private DBInfoData _DBInfoData = null;
public ClassA(DBInfoData dbInfoData)
{
_DBInfoData = dbInfoData;
}
public void MethodA()
{
throw new NotImplementedException();
}
public void MethodB()
{
throw new NotImplementedException();
}
}
//=== Internal access only ClassB
internal class ClassB : ICommon
{
private WebInfoData _WebInfoData = null;
public ClassB(WebInfoData webInfoData)
{
_WebInfoData = webInfoData;
}
public void MethodA()
{
throw new NotImplementedException();
}
public void MethodB()
{
throw new NotImplementedException();
}
}
3) Data Model class as below:
//=== Database Information
public class DBInfoData
{
public string Server { get; set; }
public string Database { get; set; }
}
//=== Web Server Information
public class WebInfoData
{
public string URL { get; set; }
public int Port { get; set; }
}
Now I want to implement generic functionality of C# where in factory class I do not want to declare two overload method. Using single method I can return ClassA or ClassB based on Data Model pass.
You could edit the Init method without having to edit anything else. This method will take a generic type parameter T, which can be of any type. Then you can use the is operator, which according to the docs used to type testing. You need to check however for any unsupported type of T, because you didn't add any constraint to the generic type passed. A raw implementation would be:
public class Factory
{
public ICommon Init<T>(T infoData)
{
if (infoData is DBInfoData dbInfoData) {
return new ClassA(dbInfoData);
}
if (infoData is WebInfoData webInfoData) {
return new ClassB(webInfoData);
}
throw new Exception($"Cannot create instance for info data of type {infoData.GetType().Name}");
}
}
And to test it:
var factory = new Factory();
var t1 = factory.Init(new DBInfoData()); // will be ClassA
var t2 = factory.Init(new WebInfoData()); // ClassB
To sophisticate it, you could introduce type constraint on your generic T class to make sure you can only pass appropriate types. For the current situation, you could create a marker interface for your classes DBInfoData and WebInfoData by introducing an empty interface say IInfoData. Then you have to inherit your classes like this:
public interface IInfoData {}
public class DBInfoData : IInfoData
{
public string Server { get; set; }
public string Database { get; set; }
}
public class WebInfoData : IInfoData
{
public string URL { get; set; }
public int Port { get; set; }
}
Now both inherits from (actually 'marked by') your base interface. Introduce a constraint to your factory to allow only descendants of IInfoData to be passed as an argument (so either DBInfoData or WebInfoData) by adding a constraint shown in the docs I linked above:
public class Factory
{
public ICommon Init<T>(T infoData) where T: IInfoData
{
if (infoData is DBInfoData dbInfoData) {
return new ClassA(dbInfoData);
}
if (infoData is WebInfoData webInfoData) {
return new ClassB(webInfoData);
}
throw new Exception($"Cannot create instance for info data of type {infoData.GetType().Name}");
}
}
Any type other than the descendants of IInfoData will cause a compilation error, and you're done. Use it like in my previous example:
var factory = new Factory();
var t1 = factory.Init(new DBInfoData()); // will be ClassA
var t2 = factory.Init(new WebInfoData()); // ClassB

Why do I get NullReferenceException in my factory pattern implementation, c#?

Main class:
public class ClP_Login
{
private Form vrcView;
private I_Repository<I_Identifiable> vrcRepository = null;
public ClP_Login(Form vrpView)
{
vrcView = vrpView;
SetTheme();
}
private void SetTheme()
{
if(vrcView !=null)
vrcView.BackColor = Cl_BaseColor.StandardBackground;
}
public void CreateNewUser()
{
ClE_User test = new ClE_User();
test.Name = "test name";
test.Password = "";
Cl_RepositoryFactory vrlFactory = new Cl_RepositoryFactory();
vrcRepository = vrlFactory.CreateRepository(E_Repositories.User);
vrcRepository.Add(test);
}
}
Cl_RepositoryFactory class:
public class Cl_RepositoryFactory
{
public virtual I_Repository<I_Identifiable> CreateRepository(E_Repositories vrpRepository)
{
I_Repository<I_Identifiable> vrlRepository = null;
switch (vrpRepository)
{
case E_Repositories.User:
vrlRepository = new Cl_UserRepository() as I_Repository<I_Identifiable>;
break;
}
return vrlRepository;
}
}
Enum E_Repositories:
public enum E_Repositories
{
User
}
I_Identifiable Interface:
public interface I_Identifiable
{
int Id { get; set; }
}
I_Repository Interface:
public interface I_Repository<T>
{
T GetById(Guid id);
T GetByQuery(Queue query);
void Add(T item);
void Remove(T item);
void Update(T item);
}
Cl_UserRepository class:
public class Cl_UserRepository : I_Repository<ClE_User>
{
public void Add(ClE_User item)
{
MessageBox.Show("Created new User");
}
public ClE_User GetById(Guid id)
{
throw new NotImplementedException();
}
public ClE_User GetByQuery(Queue query)
{
throw new NotImplementedException();
}
public void Remove(ClE_User item)
{
throw new NotImplementedException();
}
public void Update(ClE_User item)
{
throw new NotImplementedException();
}
}
And ClE_User class:
public class ClE_User : I_Identifiable
{
public int Id { get; set; }
public string Name { get; set; }
public string Password { get; set; }
}
The question is, why do I get null reference exception using vrcRepository?
vrlFactory.CreateRepository(E_Repositories.User); return null and I don't have any idea why, please help
In CreateRepository method try to remove casting statement as I_Repository<I_Identifiable>. If your code will not compile, that will mean Cl_UserRepository is not compatible with I_Repository<I_Identifiable>.
Otherwise everyting is correct with CreateRepository method
ClE_User inherits from I_Identifiable, but I_Repository<ClE_User> does not inherit from I_Repository<I_Identifiable>. Those are different interfaces as far as C# is concerned.
To elaborate more, you have I_Repository<I_Identifiable> vrcRepository which should in theory take I_Repository of any I_Identifiable kind. So let's say you initialize this member to some other, for instance I_Repository<ClE_SomethingOtherThanUser>. But then you call vrcRepository.Add(test). That's not going to work, with test being ClE_User.
Now, first remove the as I_Repository<I_Identifiable> part, and then to make it compile make I_Repository just a plain dumb non-generic interface, whose methods take I_Identifiable parameter or return I_Identifiable value. This may not be what you wanted, but it will compile.
EDIT
I realize that the enum will trigger. You are right
new Cl_UserRepository() as I_Repository
CL_UserRepository has to implement the interface you are trying to return, and then you don't need to type cast it at all. Sorry! I owe you a case of beer.

Generic conversion issue

I'm trying to design a pattern to orchest several operations. Each operation would take a parameter and deliver a result. That result might or might not be used by the following operation. This is a simplified version of the design, but if you copy/paste this on a console projecto it will "work" (there's a compiling error I can't get fixed).
Error
The type
'ConsoleApplication1.InternalDebit'
cannot be used as type parameter 'T1' in the generic type or method
'ConsoleApplication1.Orchestrator.Add(T1)'. There is no implicit
reference conversion from
'ConsoleApplication1.InternalDebit'
to
'ConsoleApplication1.Operation'. c:\projects\BCP\BaseMvc\ConsoleApplication1\ConsoleApplication1\Program.cs 17 13 ConsoleApplication1
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var internalDebit = new InternalDebit<InternalDebitParameter, InterbankCreditParameter>(new InternalDebitParameter() { Id = 1 });
var orchestrator = new Orchestrator();
// error here!
orchestrator.Add(internalDebit);
}
}
public interface IParameter
{
}
public interface IResult
{
}
public interface IReversible
{
void Reverse();
}
public interface IOperation<T, R>
where T : class, IParameter
where R : class, IResult
{
Type ParameterType { get; }
Type ResultType { get; }
T Parameter { get; set; }
R Execute(T parameter);
}
public abstract class Operation<T, R> : IOperation<T, R>
where T : class, IParameter
where R : class, IResult
{
public virtual R Execute(T parameter)
{
this.Parameter = parameter;
return default(R);
}
public Type ParameterType
{
get { return typeof(T); }
}
public Type ResultType
{
get { return typeof(R); }
}
public T Parameter { get; set; }
public Operation(T parameter)
{
this.Parameter = parameter;
}
}
public class InternalDebitParameter : IParameter
{
public int Id { get; set; }
}
public class InterbankCreditParameter : IParameter, IResult
{
public int Id { get; set; }
}
public class InternalDebit<T, R> : Operation<T, R>
where T : class, IParameter
where R : class, IResult
{
public InternalDebit(T parameter)
: base(parameter)
{
}
public override R Execute(T parameter)
{
return new InterbankCreditParameter() { Id = 2 } as R;
}
}
public class Orchestrator
{
public List<Operation<IParameter, IResult>> Operations { get; private set; }
public List<IParameter> Parameters { get; private set; }
public void Add<T1>(T1 t) where T1 : Operation<IParameter, IResult>
{
this.Operations.Add(t);
}
public void SetUpParameters(params IParameter[] parameters)
{
this.Parameters = new List<IParameter>();
parameters.ToList().ForEach(s => this.Parameters.Add(s));
}
public void Play()
{
IParameter generalResult = null;
foreach (var instrument in this.Operations)
{
var parameter = this.Parameters.FirstOrDefault(s => s.GetType() == instrument.ParameterType);
if (parameter == null)
{
IResult actualResult = null;
if (generalResult != null)
{
try
{
actualResult = instrument.Execute(generalResult);
}
catch (Exception ex)
{
if (instrument is IReversible)
((IReversible)instrument).Reverse();
else
throw;
break;
}
finally
{
if (actualResult is IParameter)
generalResult = (IParameter)actualResult;
}
}
else
{
throw new Exception("Orchetrator missconfiguration.");
}
}
}
}
}
}
If you play a little with covariance/contravariance you may be able to do something similar to what you're after. Or anyway, the compiler will tell you more precisely where what you're trying to do is not type-safe.
First step: the error you're getting states that There is no implicit reference conversion from 'InternalDebit<InternalDebitParameter,InterbankCreditParameter>' to 'Operation<IParameter,IResult>'.
So, since InternalDebit implements IOperation, the first thing you can do is make IOperation covariant, trying to define it as:
public interface IOperation<out T, out R>
This would mean that a variable of type IOperation<IParameter,IResult> would happily accept a value of type Operation<InternalDebitParameter,InterbankCreditParameter>, which is one step closer to what you want.
You would then have your Add's method signature constrained in terms of IOperation instead of Operation
public void Add<T1>(T1 t) where T1 : IOperation<IParameter, IResult>
The compiler tells us something's wrong:
Invalid variance: The type parameter 'T' must be invariantly valid on 'IOperation<T,R>.Parameter'. 'T' is covariant.
Invalid variance: The type parameter 'T' must be contravariantly valid on 'IOperation<T,R>.Execute(T)'. 'T' is covariant.
That's the first indication of why this code is unsound. Covariant parameters can only be used "on the way out" of function (i.e. as a return type), not as "in" parameters.
Second step making IOperation covariant. This may be painful and change your code, as it means changing Execute not to accept parameters of type T.
public interface IOperation<out T, out R>
where T : class, IParameter
where R : class, IResult
{
Type ParameterType { get; }
Type ResultType { get; }
T Parameter { get; /*set;*/ } //can't allow the interface to set T
// R Execute(T parameter); // can't have an Execute with T as a parameter
R Execute(); // you can however inject T in the constructor of the
// inherited class and call Execute without parameters
}
Third step you now get a new error:
The best overloaded method match for 'System.Collections.Generic.List<Operation<IParameter,IResult>>.Add(Operation<IParameter,IResult>)' has some invalid arguments
This is again a covariance issue. List is not covariant and you can't Add t to a List.
I don't really know what to suggest,since I don't want to change completely the intent of your code (especially since I can't say I fully understand it...)
You may find something useful in this answer, for instance:
Covariance and IList
You're taking generics too far into C++ templating power. On the line that gives the error you're implicitly creating the function:
public void Add(InternalDebit<InternalDebitParameter, InterbankCreditParameter>);
As declared, this class inherits from:
Operation<InternalDebitParameter, InterbankCreditParameter>
The generic requirement howeveer states that T1 should be of type Operation<IParameter, IResult>, which it isn't, even though both parameters do inherit from the correct types, since there is no polymorphism allowed.
What you're trying to achieve here is inherently impossible with generics (or templates in C++ actually) because you are specifying way too much, and specifying inheritance requirements that can never be satisfied. You need to remember that generics are in a way just a luxury shorthand of writing many classes with only a little bit of code, they do not introduce recursive polymorphism all of a sudden.
Long story short, rewrite the code to use inheritance and base classes rather than depending on generics. I suspect your entire pattern is possible without a single generic and just as type safe.
Ok, for the sake of completeness of this post, I'll show you how I finally get this working.
It can be better, I'm still open to suggestions. Unfortunatelly I got to move on from this task, it's already delayed.
I'll post and edit to this answer in order to follow up it on Code Review site.
Copy/Paste in a console application, it's a fully functional code example.
class Program
{
static void Main(string[] args)
{
var transferenceInfo = new InterbankTranferenceInfo();
var orchestrator = new Orchestrator(new InternalDebitOperation(transferenceInfo),
new InterbankCreditOperation(),
new CommissionOperation());
orchestrator.Run();
}
}
public class InterbankTranferenceInfo : IParameter
{
public bool InternalDebitDone { get; set; }
public bool InterbankCreditDone { get; set; }
public bool CommissionDone { get; set; }
}
public class InternalDebitOperation : Operation<InterbankTranferenceInfo>, IOperation<InterbankTranferenceInfo>
{
public InternalDebitOperation(InterbankTranferenceInfo parameter)
: base(parameter)
{
}
public override InterbankTranferenceInfo Execute()
{
return new InterbankTranferenceInfo() { InternalDebitDone = true };
}
}
public class InterbankCreditOperation : Operation<InterbankTranferenceInfo>, IOperation<InterbankTranferenceInfo>
{
public override InterbankTranferenceInfo Execute()
{
Parameter.InterbankCreditDone = true;
return Parameter;
}
}
public class CommissionOperation : Operation<InterbankTranferenceInfo>, IReversible, IOperation<InterbankTranferenceInfo>
{
public override InterbankTranferenceInfo Execute()
{
Parameter.CommissionDone = true;
// Uncomment this code to test Reverse operation.
// throw new Exception("Test exception, it should trigger Reverse() method.");
return Parameter;
}
public void Reverse()
{
Parameter.CommissionDone = false;
}
}
public enum OperationStatus
{
Done,
Pending,
Reversed
}
public interface IParameter
{
}
public interface IReversible
{
void Reverse();
}
public interface IOperation<out T> : IInternalOperation<T> where T : IParameter
{
}
public interface IInternalOperation<out T> : IExecutableOperation<T>
{
bool GetParameterFromParentOperation { get; }
OperationStatus Status { get; set; }
IParameter Execute(IParameter parameter);
}
public interface IExecutableOperation<out T>
{
T Execute();
}
//[System.Diagnostics.DebuggerStepThroughAttribute()]
public abstract class Operation<T> : IInternalOperation<T> where T : IParameter
{
public T Parameter { get; private set; }
public bool GetParameterFromParentOperation { get { return this.Parameter == null; } }
public OperationStatus Status { get; set; }
public Operation()
{
Status = OperationStatus.Pending;
}
public Operation(IParameter parameter)
{
Status = OperationStatus.Pending;
this.Parameter = (T)parameter;
}
public abstract T Execute();
public virtual IParameter Execute(IParameter parameter)
{
this.Parameter = (T)parameter;
return this.Execute();
}
}
public class Orchestrator
{
public List<IOperation<IParameter>> Operations { get; private set; }
public Orchestrator(params IOperation<IParameter>[] operations)
{
this.Operations = new List<IOperation<IParameter>>();
foreach (var item in operations)
{
this.Operations.Add((IOperation<IParameter>)item);
}
}
public IParameter Run()
{
IParameter previousOperationResult = null;
foreach (var operation in this.Operations)
{
try
{
if (operation.GetParameterFromParentOperation)
previousOperationResult = operation.Execute(previousOperationResult);
else
previousOperationResult = operation.Execute();
operation.Status = OperationStatus.Done;
}
catch (Exception)
{
foreach (var o in this.Operations)
{
if (o is IReversible)
{
((IReversible)o).Reverse();
o.Status = OperationStatus.Reversed;
}
else
throw;
}
break;
}
}
return previousOperationResult;
}
}
EDIT
Code Review Post

Generic interface compiles but does not work at runtime

I have an issue with generic interface. The compiler does not give any compiling errors but at run-time unseen exception is thrown.
public interface IStructure
{
string Name {get;}
}
public interface IStructureNavigation<T> : IStructure where T : IStructure
{
T Parrent {get;}
}
public class ResourceStructure : IStructureNavigation<ResourceStructure>
{
private ResourceStructure _parrent;
public virtual string Name
{
get;
set;
}
public virtual ResourceStructure Parrent
{
get { return _parrent; }
}
}
Can someone explain why does the following code fail at runtime?
public class Action
{
private ObjectContext _context;
private ObjectSet<ResourceStructure> _structue;
private IQueryable<ResourceStructure > _parrents;
public Action()
{
string connectionString =
ConfigurationManager
.ConnectionStrings["Structure"].ConnectionString;
_context = new ObjectContext(connectionString);
_context.ContextOptions.LazyLoadingEnabled = true;
_structue = _context.CreateObjectSet<ResourceStructure>();
_parrents = _structue.Where(x => x.ParentID == null);
// FAILS IN FOREACH LOOP : UNSEEN EXCPTION
foreach (IStructureNavigation<IStructure> strt in _parrents)
{
//do something
}
//WORKS IF USING CONCRETE TYPE NOT INTERFACE
foreach(IStructureNavigation<ResourceStructure > strt in _parrents)
{
//do something
}
}
}
Declare T as covariant
public interface IStructureNavigation<out T> : IStructure where T : IStructure
That's because your instance is of type IStructureNavigator<ResourceStructure> and not IStructureNavigator<IStructure>.
If you need to use the interface, you can use the Cast extension method:
_parrents = _context.CreateObjectSet<ResourceStructure>().Cast<IStructure>();
Which version of the Framework are you using?

Categories