Making covariant interface backward compatible - c#

We have an interface to deal with DAL with pretty simple definition:
interface IRepository<T> : IQueriable<T> // so we can read data from database
{
Save(T document); // dozen of methods here
}
Mostly we use two implementations: real version and in memory version for unit testing. Here is declarations of one of class:
public RealRepository : IRepository<AccountEntity> { ... }
// typical IOC usage
services.AddSingleton<IRepository<AccountEntity>, RealRepository<AccountEntity>>();
Now we are working to spin off for main codebase to custom version of project and we need custom fields in data and occassional custom behavior in repository. Most of classes are fine with base implementation but others would require specific implementation. So my goal is to get to following services in:
var repository = new RealRepository<CustomAccountEntity>();
services.AddSingleton(IRepository<AccountEntity>, repository);
// for new classes
services.AddSingleton(IRepository<CustomAccountEntity>, repository);
I tried to add out T to IRepository but I am using T in input parameters and this gave compile time "Invalid variance" error.
I can see a solution by adding second type parameter to interface so it looks like:
IRepository<TBase, out TChild> : IQueriable<TChild> {
Save (T document);
}
Finally, Question: How can make change 100% backward compatible?
What I tried:
Add IRepository<T>: IRepository<T,T> -> complies, but RealRepository is not implementing IRepository anymore.
Add 2 interfaces in implementation: public class RealRepository<TBase, TChild>: IRepository<TBase, TChild>, IRepository<TChild> but this gives compliation error 'cannot implement both ... and ... because they may unify for some type parameter substitutions'

Save(T document) has T in a contravariant position. That means in T, not out T.
Let's recap what contravariance means. Suppose you had this code:
using System;
public class Entity {}
public class AccountEntity : Entity {}
public class CustomAccountEntity : AccountEntity {}
public interface IQueryable<in T>
where T : Entity
{}
public interface IRepository<in T>
where T : Entity
{
void Save(T record);
}
public class EntityRepository<T> : IRepository<T>
where T : Entity
{
public void Save(T record) {}
}
public class Program
{
public static void Main()
{
// This is ***VALID***:
IRepository<CustomAccountEntity> repo = new EntityRepository<AccountEntity>();
Console.WriteLine(repo == null ? "cast is invalid" : "cast is valid");
}
}
https://dotnetfiddle.net/cnEdcm
So whenever you need a IRepository<CustomAccountEntity>, you can use a concrete EntityRepository<AccountEntity> instance. Seems counter-intuitive, but it's actually totally right: If the concrete method is Save(AccountEntity), it can obviously handle CustomAccountEntity instances too; OTOH if the concrete method were Save(CustomAccountEntity), it would NOT be able to handle simple AccountEntity instances.
Having said that, then I think you should
Use contravariance instead;
Declare all dependencies using the most specialised type, e.g. IRepository<CustomWhateverEntity>;
In the IoC registration code, for each particular entity, setup either Repository<CustomeWhateverEntity>, if you need the extra behaviour, or just Repository<WhateverEntity> otherwise.

Related

How to pass a class constructor as parameter in C#

I want to create generic Unit Test classes for Services. My base class is as generic as possible and I wanna pass the Service constructor as a parameter to my base class from the derived class, but I don't no how to do it in C#.
public interface IBaseServiceUnitTest<TEntity> where TEntity : BaseEntity
{
//...some methods
}
public class BaseServiceUnitTest<TEntity> : IBaseServiceUnitTest<TEntity> where TEntity : BaseEntity
{
private IBaseService<TEntity> _service;
public BaseServiceUnitTest(Constructor ctor)
{
_service = ctor();
}
//...implemented methods from IBaseServiceUnitTest
}
public class CustomEntityServiceUnitTest : BaseServiceUnitTest<CustomEntity>
{
public CustomEntityServiceUnitTest()
: base(Constructor ctor)
}
I think a factory method would serve you well here.
Mark your base test fixture as abstract and define a protected abstract method with the same signature as the service constructors. Then, call that method in your base fixture's setup logic.
You will have to implement the abstract method for each derived test class, but I think it's a reasonable compromise.
Note that I also removed the interface from the test class. Based on the sample code you provided, it's entirely redundant with the now-abstract base class. Of course, it might be useful for some reason not apparent from your example--if so, you can keep it.
public class BaseServiceUnitTest<TEntity> where TEntity : BaseEntity
{
private IBaseService<TEntity> _service;
public BaseServiceUnitTest(Constructor ctor)
{
_service = Create(/* your mocked dependencies here */);
}
protected abstract IBaseServce<TEntity> Create(Dependency1 d1, Dependency2 d2);
//...implemented methods from IBaseServiceUnitTest
}
public class CustomEntityServiceUnitTest : BaseServiceUnitTest<CustomEntity>
{
// "arg1, arg2"
protected override IBaseService<CustomEntity> Create(Dependency1 d1, Dependency2 d2) =>
new BaseService<CustomerEntity>(d1, d2);
}
Addendum
If you really want to make things automagic, you could try the answer to this question. It'll work, but you'll sacrifice "F12-ability" (the ability to find and navigate through references using Visual Studio's shortcuts) and compile-time verification of your constructors and their arguments. Personally, I'd probably use the factory method.
Addendum #2
For completeness, it's also worth noting that if your service-under-test had no constructor arguments, you might also be able to use the new constraint. Based on your comments, it doesn't sound like it will work in this case, but it might be useful another time.

C# 8 default interface implementation and inheritance

I want to use C# 8 default interface implementation to face a performance issue in my code.
Actually, I have this intefaces :
public interface IDataAdapter {}
public interface IDataAdapter<T> : IDataAdapter
{
void Insert(T value);
}
I actually have to do reflection across all IDataAdapter, check generic type and call Insert by reflection for a specific T instance. What I wish to do is :
public interface IDataAdapter
{
void InsertValue(object value);
}
public interface IDataAdapter<T> : IDataAdapter
{
void Insert(T value);
public void InsertValue(object value) => Insert(value as T);
}
The compiler says to use the keyword new to mask the inherited method. However, the only thing I'm trying to accomplish is to have a non-generic method already implemented to make all IDataAdapter<T> implementations to only have to implement the generic version.
Is this something I can accomplish or it's still impossible ? I already know that using an abstract class is a way to solve this issue, but I want to allow a developper to have a class that implements many IDataAdapter...
This is my current reflection code :
public IEnumerable<IDataAdapter> DataAdapters { get; }
public Repository(IEnumerable<IDataAdapter> dataAdapters)
{
DataAdapters = dataAdapters;
}
public async Task SaveAsync()
{
foreach (var item in aggregates)
{
foreach (var dataAdapter in DataAdapters)
{
if (dataAdapter.GetType().GetInterfaces().Any(i => i.IsGenericType && i.GetGenericArguments()[0] == item.GetType()))
{
dataAdapter.GetType().GetMethod("Insert", new[] { item.GetType() }).Invoke(dataAdapter, new[] { item });
}
}
}
}
From an object oriented point of view, what you are trying to do can't be done.
Suppose you create the following class hierarchy:
public interface IFoo{}
public interface IBar{}
public class A: IFoo{}
public class B: IFoo{}
public class C:IFoo,IBar {}
And then the following adapters:
public class TestA : IDataAdapter<A>{}
public class TestB : IDataAdapter<B>{}
public class TestC : IDataAdapter<C>{}
public class TestIFoo : IDataAdapter<IFoo>{}
public class TestIBar : IDataAdapter<IBar>{}
public class TestIBoth : IDataAdapter<IFoo>,IDataAdapter<IBar>{}
What should happen if TestA receive an instance of A is quite easy. But what about TestIFoo receive a C? Currently your reflection code won't work because you test type equality (does C equals IFoo? No! Even if C as IFoo is ok).
This breaks Liskov substitution principle. If something works with a class then it should also work with any of its subclasses.
Let's suppose you fix above point. Now what about TestIBoth receiving a C? Is there two different implementation of Insert in it? Of course, this is required by inheritence! But then... do you have to insert C twice? Or do you have to insert it just once in the first fitting method?
The reason why you have to go through reflection is because all those questions needs an algorithmic answer. Your compiler won't be able to answer (which makes the language prevent it by the way)
In the end I would strongly recommend to use a very different solution (like the one proposed by Wim Coenen)
I recognize this problem where you need to look up the IDataAdapter implementation which knows how to handle a certain type of item. I've done something similar for a "view plugin" system, where I would look for the view plugin that knows how to render a certain type. This is useful if you can't know in advance what type of objects you'll need to render.
As far as I know, trying to shoehorn more compile-time type safety into this pattern won't really work, or if it does then it won't actually provide any benefits. I would just declare IDataAdapter like this:
public interface IDataAdapter
{
void InsertValue(object value);
Type SupportedType { get; }
}
If a data adapter supports multiple types, you can make it IEnumerable<Type> SupportedTypes instead, or maybe replace the property by a bool SupportsType(Type) method.

How do I write an interface or abstract class that specifies creation logic?

I have a generic class that deals with widgets that can be deserialized from strings. Instances of the generic class will take the type of one of these widgets as a template parameter, and then create these widgets from strings. I wish to use the covariance properties of C#'s generics to write code like WidgetUser<IWidget> to deal with objects that may be WidgetUser<RedWidget> or WidgetUser<BlueWidget>. The problem is that to create a widget from a string inside of WidgetUser<T>, I'm forced to add new() as a guard. This makes WidgetUser<IWidget> an invalid type. Currently, I have code like this:
interface IWidget
{
// Makes this widget into a copy of the serializedWidget
void Deserialize(string serializedWidget);
}
class WidgetUser<T> where T : IWidget, new()
{
public void MakeAndUse(string serializedWidget)
{
var widget = new T();
widget.Deserialize(serializedWidget);
Use(widget);
}
}
With this code, I can make WidgetUser<BlueWidget> just fine, because BigWidget satisfies new(). I cannot write WidgetUser<IWidget> because instances of IWidget (or an equivalent abstract class) are not guaranteed to work with new(). A workaround could be this:
abstract class WidgetUser
{
public abstract void MakeAndUse();
}
class WidgetUser<T> : WidgetUser
where T : IWidget, new()
{
/* same as before but with an 'override' on MakeAndUse */
}
With this code, I can create a WidgetUser<BlueWidget> then write code that deals with just WidgetUser. I could have similar code with an abstract class BaseWidget instead of IWidget that accomplishes almost the same thing. This is functional, but I suspect there is a more direct approach that doesn't force me to define a dummy class. How can I convey my intent to the type system without creating dummy classes or extra factories. I just want an interface that says "you can make one of these from a string".
TL;DR:
Is there some way to write an interface or abstract class that lets me create an instance from a string but doesn't require me to have new() as a guard on WidgetUser<T>?
The problem here is that your Deserialize() method should be a static method. Therefore it should not be a member of IWidget itself - it should be a member of a factory interface, or it should be a static member of a concrete Widget class which is called from a concrete factory method. I show the latter approach below.
(Alternatively, you could use a Func<IWidget> delegate to specify it, but it's more usual to provide a full factory interface.)
So I suggest you create the factory interface:
interface IWidgetFactory
{
IWidget Create(string serialisedWidget);
}
Then remove the Deserialize() from IWidget:
interface IWidget
{
// .. Whatever
}
Then add a static Deserialize() method to each concrete implementation of IWidget:
class MyWidget: IWidget
{
public static MyWidget Deserialize(string serializedWidget)
{
// .. Whatever you need to deserialise into myDeserializedObject
return myDeserializedObject;
}
// ... Any needed IWidget-implementing methods and properties.
}
Then implement the factory for your concrete widget class using the static Deserialize() method from the concrete widget class:
sealed class MyWidgetFactory : IWidgetFactory
{
public IWidget Create(string serialisedWidget)
{
return MyWidget.Deserialize(serialisedWidget);
}
}
Then add a constructor to your WidgetUser class which accepts an IWidgetFactory and use it in MakeAndUse():
class WidgetUser
{
public WidgetUser(IWidgetFactory widgetFactory)
{
this.widgetFactory = widgetFactory;
}
public void MakeAndUse(string serializedWidget)
{
var widget = widgetFactory.Create(serializedWidget);
Use(widget);
}
private readonly IWidgetFactory widgetFactory;
}
Note that in this scenario, you no longer need the type argument for WidgetUser, so I have removed it.
Then when you create the WidgetUser you must supply a factory:
var widgetUser = new WidgetUser(new MyWidgetFactory());
...
widgetUser.MakeAndUse("MySerializedWidget1");
widgetUser.MakeAndUse("MySerializedWidget2");
Passing in a factory allows a lot more flexibility.
For example, imagine that your serialization scheme included a way of telling from the serialized string which kind of widget it is. For the purposes of simplicity, assume that it starts with "[MyWidget]" if it's a MyWidget and starts with ["MyOtherWidget"] if it's a MyOtherWidget.
Then you could implement a factory that works as a "virtual constructor" that can create any kind of Widget given a serialization string as follows:
sealed class GeneralWidgetFactory: IWidgetFactory
{
public IWidget Create(string serialisedWidget)
{
if (serialisedWidget.StartsWith("[MyWidget]"))
return myWidgetFactory.Create(serialisedWidget);
else if (serialisedWidget.StartsWith("[MyOtherWidget]"))
return myOtherWidgetFactory.Create(serialisedWidget);
else
throw new InvalidOperationException("Don't know how to deserialize a widget from: " + serialisedWidget);
}
readonly MyWidgetFactory myWidgetFactory = new MyWidgetFactory();
readonly MyOtherWidgetFactory myOtherWidgetFactory = new MyOtherWidgetFactory();
}
Note that this is generally not the best way to do things - you are better using a Dependency Container such as Autofac to manage this kind of thing.
I would implement WidgetFactory and call WidgetFactory.Create<T>(serializedWidget) to avoid the usage of new T()

How to set a constraint for a type so it must be of another generic typed type

This is probably asked before but I can't work it out. Maybe if I could get the title right I could goolge it.
I have got this generic repository interface:
public interface IRepository<TEntity>
{
TEntity Resolve<TEntity>(); // dummy function, just to get the idea
}
I also have a generic unit of work, which is able to resolve a generic repository:
public interface IUnitOfWork
{
IRepository<TEntity> GetGenericRepository<TEntity>() where TEntity : class;
}
So far so good.
But as real life continues, I would like to create a custom repository, with some specific funtions. So I was thinking: inheritance; like this:
public class SpecialRepository : IRepository<SomeEntityType>
{
public void SomeSpecialFunction() { };
}
Obviously, this type cannot be resolved with the GetGenericRepository methode so I thought: lets add a extra method to the IUnitOfWork interface:
public interface IUnitOfWork
{
//same old get generic repository
IRepository<TEntity> GetGenericRepository<TEntity>() where TEntity : class;
//the newly added.
T GetInheretedRepository<T>() where T : class;
}
I want to be able to call the unit of work with the special repository, something like this:
public test()
{
IUnitOfWork uow = new UnitOfWork();
//I want to make this call with a constraint on TemplateRepo
//to enforce it's type: IRepository<T> (which TemplateRepo is)
var y = uow.GetInheretedRepository<TemplateRepo>();
}
The question is: how can I restrict type T in T GetInheretedRepository<T>() where T : class; to be of type: IRepository<TEntity>?
I tried this:
public interface IUnitOfWork
{
//the newly added.
//error: Only class or interface could be specified as constraint
T GetInheretedRepository<T>() where T : class, IRepository; }
and
public interface IUnitOfWork
{
//the newly added.
//error: type argument missing
T GetInheretedRepository<T>() where T : class, IRepository<>;
}
that doesnt work.
I could drop the constrain as a quick-fix or perhaps create an inherited unit of work, but then; the question still remains.
The way to do this is by adding a second generic type argument, as follows:
TRepository GetInheretedRepository<TRepository, TEntity>()
where TRepository : IRepository<TEntity>
where TEntity : class;
Here you supply both the Repository type and the entity type. This way the C# compiler can check whether or not the type matches. Here's how to call it:
var rep = uow.GetInheretedRepository<SpecialRepository, SomeEntityType>();
rep.SomeSpecialFunction();
This obviously sucks, since you will have to specify both types. But more importantly, this sucks because you have to specify the concrete type, making your code take a dependency on a concrete type; a violation of the Dependency Inversion Principle.
I really would like to advice to to step away from a design where you depend on a concrete type, or even better, step away from a design where you have many methods on a specific repository class, because this violates both SRP, OCP and ISP and this will likely cause maintenance problems later on.
So instead, take a look at the application design that is described in this article.
You need to specify second Type like
public interface IUnitOfWork
{
//the newly added.
T GetInheretedRepository<T, TEntity>() where T : class, IRepository<TEntity>;
}
public interface IRepository<TEntity>
{
TEntity Resolve(); // dummy function, just to get the idea
}
example that compiles fine - https://dotnetfiddle.net/MmmPil

Generics problem with Unit of Work Pattern

I need some help with the design of the Unit of Work + Repository + IoC pattern. I have several interfaces defined as follows:
public interface IRepository<T>
{
T GetEntity(int id);
}
public interface IUserRepository : IRepository<User>
{
User GetUserByXyz(int id);
}
public interface IUnitOfWork
{
T Respository<T>() where T : IRepository<T>;
}
I am using Unity to resolve some references. Here's the implementation of the UoW:
public class UnitOfWork : IUnitOfWork
{
public T Respository<T>() where T : IRepository<T>
{
var container = new UnityContainer();
return container.Resolve<T>();
}
}
Now i am having trouble calling the interface:
User user = _unitOfWork.Respository<IUserRepository>().GetUserByXyz(1);
The type 'IUserRepository' cannot be used as type parameter 'T' in
the generic type or method 'IUnitOfWork.Respository()'. There is no
implicit reference conversion from 'IUserRepository' to
'IRepository'.
How do get around the generic constraint error?
Expanding on my comment:
The statement public T Respository<T>() where T : IRepository<T> implies that you're expecting a type that is a Repository of itself, e.g. IUserRepository would have to be an IRepository<IUserRepository> to satisfy your condition.
You need two different generics, one for the item that is held in the reporsitory TItem and another for the repository itself, TRepo.
Then the whole code becomes:
public interface IRepository<TItem>
{
TItem GetEntity(int id);
}
public interface IUserRepository : IRepository<User>
{
}
public interface IUnitOfWork
{
TRepo Respository<TRepo,TItem>() where TRepo : IRepository<TItm>;
}
and
public class UnitOfWork : IUnitOfWork
{
public TRepo Respository<TRepo,TItem>() where TRepo : IRepository<TItem>
{
var container = new UnityContainer();
return container.Resolve<TRepo>();
}
}
finally, the call becomes:
User user = _unitOfWork.Respository<IUserRepository,User>().GetEntity(1);
Initial note:
_unitOfWork.Respository<IUserRepository>()…
As it is, you're essentially "abusing" UnityOfWork as a service locator (you can ask it for any type of repository), but it doesn't seem to offer any additional benefits. Is this really what you want? Couldn't you just do away with UnitOfWork and do the following instead:
_unityContainer.Resolve<IUserRepository>()…
Alternative solution that does not require a second type parameter:
I agree with #Jon Egerton that for this to work correctly, one option would be to introduce a second generic type parameter (TItem next to TItemRepository). There is, however, another solution involving a marker interface IRepository:
// non-generic marker interface (empty)
public interface IRepository {}
public interface IRepository<T> : IRepository { … /* as before */ }
// ^^^^^^^^^^^^^
// added
public class UnitOfWork
{
public TRepository Get<TRepository>() where TRepository : IRepository
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// this way, no 2nd type parameter is
// needed since the marker interface is
// non-generic.
{
return new UnityContainer().Resolve<TRespository>();
}
}
As requested: Unit of Work example:
If you follow Martin Fowler's definition for the Unit of Work pattern, you get something rather different from what you've got right now. Rather, a Unit of Work according to his udnerstanding merely keeps track of all changes that have been made to a collection of objects. The idea behind this is that changes aren't persisted (e.g. to a database) one at a time, but all at the same time, when requested through the unit of work object; thus the pattern's name:
class UnitOfWork<T>
{
// the UnitOfWork object tracks changes to objects of type T:
private HashSet<T> newItems;
private HashSet<T> modifiedItems;
private HashSet<T> removedItems;
public void Commit()
{
// let's say items are persisted to an RDBMS, then:
// * generate 'DELETE FROM [tableForItemsOfTypeT]' statements
// for all items in the 'removedItems' set;
// * generate 'INSERT INTO [tableForItemsOfTypeT]' statements
// for all items in the 'newItems' set;
// * generate 'UPDATE [tableForItemsOfTypeT]' statements
// for all items in the 'modifiedItems' set.
}
}
Your definition of IUnitOfWork seems a little peculiar, and it seems you've got your generic parameter constraint wrong:
public interface IUnitOfWork
{
T Respository<T>() where T : IRepository<T>;
}
I'd try to get rid of the generic parameter constraint, if possible. For example:
public interface IUnitOfWork<T>
{
IRepository<T> Respository { get; }
}
public class UnitOfWork<T> : IUnitOfWork<T>
{
public IRepository<T> Respository
{
get
{
var container = new UnityContainer();
return container.Resolve<IRepository<T>>();
}
}
}
(Admittedly, I'm not sure whether it's a good idea to constrain a UnitOfWork class to one particular object type by parameterizing it this way. You could in theory also have a UnitOfWork class that implements IUnitOfWork<T> several times, for different T, though that's probably equally unwise. Judge yourself what is most appropriate for your purposes.)
Note that you'd then also have to register your types differently. You could possibly also get rid of IUserRepository this way.
P.S.: Probably, Repository does make more sense if it's a method, and not a property, as shown above. I'd choose based on how costly it is to "get" a repository. If it's expensive, make it a method; if it's a cheap operation, a property might be just fine. If you keep it as a method, I'd rename it to GetRepository to better adhere to the common .NET naming guidelines. Alternative approach:
public interface IUnitOfWork
{
IRepository<T> GetRespository<T>()
}
You are confusing your Generic constraint:
public T Respository<T,U>() where T : IRepository<U>
User user = _unitOfWork.Respository<IUserRepository,User>().GetEntity(1);

Categories

Resources