I'm working with Microsoft Code Contracts for a little while now and today I stumbled upon an awkward case. My question is - is there an elegant way to resolve this situation?
Let's assume I've got a simple trait interface for a repository which looks like this:
[ContractClass(typeof(CanAddContract)]
public interface ICanAdd {
void Add(object entity);
}
The contract for this, as denoted in the attribute, looks like this:
[ContractClassFor(typeof(ICanAdd))]
internal abstract class CanAddContract {
public void Add(object entity) {
Contract.Requires(object != null); // guard against null argument
}
}
So, now we've got a similar trait for entity deletion
[ContractClass(typeof(CanDeleteContract))]
public interface ICanDelete {
void Delete(object entity);
}
...and the contract...
[ContractClassFor(typeof(ICanDelete))]
internal abstract class CanDeleteContract {
public void Delete(object entity) {
Contract.Requires(entity != null); // guard against null argument
}
}
Nothing wrong about that. But since the interfaces denote repository traits, they are being used to compose a repository interface:
public interface IEntityStore : ICanAdd, ICanDelete {
void SomeOtherMethodThatNeedsAContract();
}
Now what? When I want to create a contract class for this interface, I have to reimplement both contract classes stated above again, since multi-inheritance isn't allowed in C#. This leaves me in a situation where I have to duplicate code for a CONTRACT. Think about that - this seems wrong to me in every possible case.
What could I do about it?
The CodeContracts compile-time rewriter will automatically discover and use the contracts for all base interfaces.
For your specific example (note how you do NOT need to repeat any of the base interfaces' contracts, and yet they still work):
using System;
using System.Diagnostics.Contracts;
namespace Demo
{
[ContractClass(typeof(CanAddContract))]
public interface ICanAdd
{
void Add(object entity);
}
[ContractClassFor(typeof (ICanAdd))]
internal abstract class CanAddContract: ICanAdd
{
public void Add(object entity)
{
Contract.Requires(entity != null);
}
}
[ContractClass(typeof(CanDeleteContract))]
public interface ICanDelete
{
void Delete(object entity);
}
[ContractClassFor(typeof(ICanDelete))]
internal abstract class CanDeleteContract: ICanDelete
{
public void Delete(object entity)
{
Contract.Requires(entity != null);
}
}
[ContractClass(typeof(EntityStoreContract))]
public interface IEntityStore: ICanAdd, ICanDelete
{
void SomeOtherMethodThatNeedsAContract(object entity);
}
// Note how we only specify the additional contract for SomeOtherMethodThatNeedsAContract().
// We do NOT need to repeat the contracts for ICanAdd and ICanDelete.
// These contracts are automatically inferred from the ICanAdd and ICanDelete contracts.
[ContractClassFor(typeof(IEntityStore))]
internal abstract class EntityStoreContract: IEntityStore
{
public void SomeOtherMethodThatNeedsAContract(object entity)
{
Contract.Requires(entity != null);
}
public abstract void Add(object entity);
public abstract void Delete(object entity);
}
public sealed class EntityStore: IEntityStore
{
public void Add(object entity)
{
}
public void Delete(object entity)
{
}
public void SomeOtherMethodThatNeedsAContract(object entity)
{
}
}
public static class Program
{
private static void Main()
{
var entityStore = new EntityStore();
entityStore.Add(null); // This will correctly give a code contracts exception.
}
}
}
Related
I found the following example, to which I have a follow up question.
stack overflow question
the existing code from the question is
public interface IRepository<T> where T : EntityObject
{
RepositoryInstructionResult Add(T item);
RepositoryInstructionResult Update(T item);
RepositoryInstructionResult Delete(T item);
}
public class Repository<T> : IRepository<T> where T : EntityObject
{
virtual RepositoryInstructionResult Add(T item)
{ //implementation}
virtual RepositoryInstructionResult Update(T item);
{ //implementation}
virtual RepositoryInstructionResult Delete(T item);
{ //implementation}
}
public class BarRepository : Repositorybase<Bar>
{
public override RepositoryInstructionResult Update(Bar item);
{
//Call base method if needed
//Base.Update(item);
//implement your custom logic here
}
}
what I would like to do is change the Update method to something like
public class BarRepository : Repositorybase<Bar>
{
// T is of Type Bar
public override RepositoryInstructionResult Update(T item);
{
//implement your custom logic here
}
}
Question: is there a way to expose the generic type in BarResposity : Repositorybase<Bar> to the methods in BarRepository?
looking for a better alternative to "search and replace" when building out the concrete class (eg make a copy of BarRespository as FooRepository and change all references from Bar to Foo). I would rather change the type in one place only.
(edit) Usage needs to remain as
var obj = new BarRepository();
Just as a note, if you're going to override all Add/Update/Delete anyways, you can make them as abstract in the RepositoryBase and then the vs suggestion is your friend:
and if there is shared logic between all of concrete classes you can put it in the abstract class and override abstract protected methods instead.
edit:
op asked for code that can do it.. well this should work.. but if you want a new concrete implementation, you'll have to create 2 classes now
public class BarRepository<T> : RepositoryBase<T> where T : Bar
{
public override int Add(T item)
{
throw new NotImplementedException();
}
public override int Update(T item)
{
throw new NotImplementedException();
}
public override int Delete(T item)
{
throw new NotImplementedException();
}
}
public class BarRepository : BarRepository<Bar>
{
}
also, if classes are so similar that copy-paste and replace is enough, maybe logic shouldn't be in separate classes but in the generic class? could you give an example of 2 classes maybe?
edit 2: another dirty trick would be to use lambdas, though personally I don't know if I would do it:
public abstract class RepositoryBase<T>
{
public Func<T, int> Add { get; protected set; }
public Func<T, int> Update { get; protected set; }
public Func<T, int> Delete { get; protected set; }
}
public class BarRepository : RepositoryBase<Bar>
{
public BarRepository()
{
Add = i => 6;
Update = i => 7;
Delete = i => 8;
}
}
It's a bit of a hack, but you could use a using alias to define the entity type:
using MyType = Bar;
public class BarRepository : Repositorybase<MyType>
{
public override RepositoryInstructionResult Update(MyType item);
{
return base.Update(item);
}
}
Now when you copy to Foo.cs, you can just change the using directive to
using MyType = Foo;
But, I would look to try and reuse as much generic code as possible, as it's not clear at all what MyType is just by looking at the methods. There's nothing wrong with a find.replace to define a new repository type that customizes actions - you just want to keep the repeated to a minimum.
IMHO any GENERIC repository is a waste of time, but if you decide to use it , what is wrong with this
public class BarRepository<T> : Repository<Bar> where T : class
{
public override void Update(Bar item)
{
}
public void Update(T item)
{
}
}
UPDATE
It looks weird but since OP wants it , you can create this code too
public class BarRepository<T> : Repository<Bar> where T : Bar
{
public override void Update(Bar item)
{
Console.WriteLine("it is Bar");
}
// T is of Type Bar
public void Update(T item)
{
Console.WriteLine("it is T");
}
}
tests
public class Bar { }
public class NoBar { }
var barRep= new BarRepository<Bar>();
barRep.Update(new Bar()); // "it is T"
var noBarRep= new BarRepository<NoBar>(); // ERROR!
UPDATE 2
since if you want
var rep = new BarRepository();
var result= rep.Update(new Bar());
you can do it the way you have done already
public class BarRepository : Repositorybase<Bar>
{
public override RepositoryInstructionResult Update(Bar item);
{
return base.Update(item);
}
}
PS
if you are still not satisfied, look at the beginning of my answer and forget about the generic repositories. Use the custom ones as the most proffesional developes do.
So I have a very big Generic class 1500+ rows and growing, with loads of methods. It has CrazyMethods and GoodMethods, I want to put the different kinds of methods in their own class but still be able to use my generic as if they were inside the generic class.
public class MyGeneric<T> : IMyGeneric<T> where T : IEntity
{
public MyGeneric(string stuff)
{
moreStuff(stuff);
}
// Region Good
public void MyGoodMethod1(T entity)
{
//does good stuff with the generic..
}
public T MyGoodMethod2()
{
//does other good stuff with the generic..
}
//Region Crazy
public void MyCrazyMethod1(T entity)
{
//does crazy stuff with the generic..
}
public T MyCrazyMethod2()
{
//does other crazy stuff with the generic..
}
}
Now in my other project where I use this generic it looks something like this
...
SomeObject _myObject = new MyGeneric<SomeObject>("ladida");
_myObject.MyGoodMethod1();
//..Other stuff
_myObject.MyCrazyMethod2();¨
...
How do I separate the methods from the MyGeneric class into separate classes (MyGenericGoodMethods.cs, MyGenericCrazyMethods.cs) but still be able to use them the way I showcased above ?
If I could use extension methods for generics that would be the perfect solution.
public static class MyGenericGoodMethods<T> where T : IEntity
{
public static T Method2(this MyGeneric<T> generic)
{
//does other good stuff with the generic..
}
}
but
Extension method can only be declared in non generic, non nested, static class
You can declare extension method in normal static class and use it with generic.
public static class MyGenericGoodMethodsExtensions
{
public static T Method2(this MyGeneric<T> generic)
{
//does other good stuff with the generic..
}
}
var myGeneric = new MyGeneric<string>();
myGeneric.Method2()
But you can always split your giant class in many separated generic classes and use them inside your main-generic class.
Split up your interfaces
public interface IMyGeneric<T>
{
void MyGeneric(string stuff);
}
public interface IMyGoodGeneric<T>
{
void MyGoodMethod1(T entity);
void MyGoodMethod2(T entity);
}
public interface IMyCrazyGeneric<T>
{
void MyCrazyMethod1(T entity);
void MyCrazyMethod2(T entity);
}
Introduce separated implementation
public class MyGeneric<T> : IMyGeneric<T> where T : IEntity
{
public void MyGeneric(string stuff)
{
// implementation
}
}
public class MyGoodGeneric<T> : IMyGoodGeneric<T> where T : IEntity
{
public void MyGoodMethod1(T entity) {}
public void MyGoodMethod2(T entity) {}
}
public class MyCrazyGeneric<T> : IMyCrazyGeneric<T> where T : IEntity
{
public void MyCrazyMethod1(T entity) {}
public void MyCrazyMethod2(T entity) {}
}
Then you can create your "giant" composition class which will implement all interfaces and use already existed implementations
public class MyGiantGeneric<T> : IMyGeneric<T>,
IMyGoodGeneric<T>,
IMyCrazyGeneric<T> where T : IEntity
{
private readonly IMyGeneric<T> _myGeneric;
private readonly IMyGoodGeneric<T> _myGoodGeneric;
private readonly IMyCrazyGeneric<T> _myCrazyGeneric;
public MyGiantGeneric(IMyGeneric<T> myGeneric,
IMyGoodGeneric<T> myGoodGeneric,
IMyGCrazyGeneric<T> myCrazyGeneric)
{
_myGeneric = myGeneric;
_myGoodGeneric = myGoodGeneric;
_myCrazyGeneric = myCrazyGeneric;
}
public void MyGeneric(string stuff)
{
_myGeneric.MyGeneric(stuff);
}
public void MyGoodMethod1(T entity)
{
_myGoodGeneric.MyGoodMethod1(entity);
}
// and so on...
}
With this approach your logic will stay in logically separated classes.
In case somewhere you need only MyGoodGeneric method you don't need to provide whole giant class and will provide only the part needed.
In case some where you want introduce another implementation only for the MyCrazy methods you will not be forced to implement MyGood methods which you don't need in this case.
Extension method can be generic, not its container class:
public static class Extensions
{
public static T Method2<T>(this MyGeneric<T> generic)
{
}
}
So Partial classes were exactly what i was looking for. Thanks to #BradleyDotNET and #AliAbdelfattah
public partial class MyGeneric<T> : IMyGeneric<T> where T : IEntity
{
public MyGeneric(string stuff)
{
moreStuff(stuff);
}
//.. other stuff
}
in MyGenericGood.cs
public partial class MyGeneric<T> where T : IEntity
{
public void MyGoodMethod1(T entity)
{
//does good stuff with the generic..
}
public T MyGoodMethod2()
{
//does other good stuff with the generic..
}
}
Is it possible to change the type of T in a method that takes a generic parameter into any kind of object when inherited. For example, I have this interface:
public interface IMethod
{
void Add<T>(T obj);
List<T> Get<T>();
void Update<T>(T obj);
void Delete<T>(T obj);
}
And I have 4 classes that are Book, Bookcase, Shelf. For each of them I have another class where I implement the methods, so I have the functionality there. Here is the Bookcasecatalog clas.
public class BookcaseCatalog: IMethod
{
private ObservableCollection<Bookcase> obsCase;
public string ConnectionString { get; set; }
public void Add(Bookcase obj)
{
}
public void Add<T>(T obj) where T : Bookcase
{
//Do smth
}
}
And when I'm done here, inherit it the interface in another class and T is a Book for example.
As you have it right now, the user can decide what kind of T he uses when calling the method Add (your constraint limits that, but thats not the idea of how to use them, they shouldn't be used at implementation.).
If you can, make your interface generic. This will allow you to decide what T is when implementing the class. Example:
public interface IMethod<T>
{
void Add<T>(T obj);
List<T> Get<T>();
void Update<T>(T obj);
void Delete<T>(T obj);
}
This will make all of your T the same type as the T in the functions
You can use it like this:
public class BookcaseCatalog: IMethod<Bookcase>
{
private ObservableCollection<Bookcase> obsCase;
public string ConnectionString { get; set; }
public void Add(Bookcase obj)
{
//Do smth
}
}
I think what you need here is a generic interface!
You should change your IMethod to this:
public interface IMethod<T> {
void Add(T obj);
List<T> Get();
void Update(T obj);
void Delete(T obj);
}
Now you get it? When you implement the interface, you are going to specify a type:
public class BookcaseCatalog : IMethod<Bookcase> {
//...
}
Then all the T's in the interface will be replaced by Bookcase:
public class Bookcase : IMethod<Bookcase> {
public void Add(Bookcase obj) {/*Do something*/}
public List<Bookcase> Get() {return something}
public void Update(Bookcase obj) {/*Do something*/}
public void Delete(Bookcase obj) {/*Do something*/}
}
That's it!
And I think it's better to learn some terminologies here. IMethod<Bookcase> is called a closed type, and IMethod<T> is called an open type.
Please note that if a method needs a parameter of an IMethod<T>, you can pass it an IMethod<Bookcase>. But if it wants an IMethod<Bookcase>, you cannot give it an IMethod<SomethingElse>. This means that closed types can be converted their open counterparts but closed types cannot be converted to other closed types unless the rules of contra- and co-variance apply.
this may be somewhere else under generic types but I cant seem to follow a lot of the answers. Apologies if this is a repeat of another question.
the following code is for a three layer app with Data, Logic and Presentation Layers
in my data layer I have a Collection of entitys and a base entity
public abstract class BaseEntity
{
int LastModifiedBy { get; set; }
DateTime LastModifiedDate{get;set;}
}
public partial class DocNum: BaseEntity
{
}
public partial class DataList: BaseEntity
{
}
in my logic layer I have a BaseDTO class for transferring data. here is the code for it
public abstract class BaseDTO
{
protected abstract void ConvertFromEntity(BaseEntity entity);
public abstract void ConvertToEntity();
}
I then go and create the implementation class DocNum based on it as follows
public class DTODocNum : BaseDTO
{
//properties here
public DTODocNum()
{
}
public DTODocNum(DocNum entity)
{
ConvertFromEntity(entity)
}
protected override void ConvertFromEntity(DocNum entity)
{
throw new NotImplementedException();
}
public override void ConvertToEntity()
{
throw new NotImplementedException();
}
}
however this will not compile telling me that no suitable method to override was found.
I know I can do the following but I want thhis method to only accept a DocNum entity from the Data Layer:
protected override void ConvertFromEntity(BaseEntity entity)
{
throw new NotImplementedException();
}
I have also tried generic types with the following
public abstract class BaseDTO
{
protected abstract void ConvertFromEntity<T>(T entity);
public abstract T ConvertToEntity<T>();
}
and the following in the derived class:
protected override void ConvertFromEntity<T>(T entity) where T:DocNum
{
throw new NotImplementedException();
}
but now the error given is Constraints for override and explicit interface implementation methods are inherited from the base method, so they cannot be specified directly
Can any one help me implement this solution so that the DTODocNum can compile whilst referring to the entity type?
Move the type parameter to the class level and add a constraint:
public abstract class BaseDTO<T> where T : BaseEntity
{
protected abstract void ConvertFromEntity(T entity);
public abstract T ConvertToEntity();
}
public class DTODocNum : BaseDTO<DocNum> { ... }
I have a class that has some methods, two of them (ADD and UPDATE) want to be generic.
Here is my class:
public class CatalogRepository : ICatalogRepository
{
public CatalogRepository(DbContext dbContext)
{
if (dbContext == null)
throw new ArgumentNullException("dbContext");
DbContext = dbContext;
}
private DbContext DbContext { get; set; }
#region Generic ADD and UPDATE
public void Add<T>(T entity) where T : DbSet
{
DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
if (dbEntityEntry.State != System.Data.Entity.EntityState.Detached)
{
dbEntityEntry.State = System.Data.Entity.EntityState.Added;
}
else
{
DbContext.Set<T>().Add(entity);
}
}
public void Update<T>(T entity) where T : DbSet
{
DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
if (dbEntityEntry.State == System.Data.Entity.EntityState.Detached)
{
DbContext.Set<T>().Attach(entity);
}
dbEntityEntry.State = System.Data.Entity.EntityState.Modified;
}
#endregion
#region SetupSensor
public IEnumerable<SetupSensor> GetSetupSensors(string masterEntity)
{
return DbContext.Set<SetupSensor>().Where(c => c.MasterEntity == masterEntity).ToList();
}
public IEnumerable<SetupSensor> ReadOnlySetupSensors(string masterEntity)
{
return DbContext.Set<SetupSensor>().AsNoTracking().Where(c => c.MasterEntity == masterEntity).ToList();
}
public SetupSensor GetSetupSensor(int sensorId)
{
return DbContext.Set<SetupSensor>().Where(c => c.SensorId == sensorId).FirstOrDefault();
}
#endregion
}
Here is the Interface Implementation:
public interface ICatalogRepository
{
SetupSensor GetSetupSensor(int sensorId);
IEnumerable<SetupSensor> GetSetupSensors(string masterEntity);
void Add<T>(T entity);
void Update<T>(T entity);
}
When I build I get the following error on the Two Generic Methods:
The constraints for type parameter 'T' of method 'CatalogRepository.Add<T>(T)' must match the constraints for type parameter 'T' of interface method 'ICatalogRepository.Add<T>(T)'. Consider using an explicit interface implementation instead.
Any clue on how to deal with this?
Well, the error is pretty self-explanatory. When implementing an interface, you must implement all its members exactly as they are defined.
Since you've introduced additional generic constraints in the implementation that are not present in the interface, implementation does not match the interface.
There are two ways to fix this: either add the constraints to the interface, or remove them from the implementation.
As a sidenote, you may want to think about making the whole interface generic, that is, to declare it like this:
// you may or may not want to have the constraint here
public interface ICatalogRepository<T> where T : DbSet
{
// sensor methods
void Add(T entity);
void Update(T entity);
}
In your implementation you do this:
public void Add<T>(T entity) where T : DbSet
{ … }
While your interface specifies this:
void Add<T>(T entity);
So, essentially, you need to make the constraints (the where part) identical for both sides. In your case, as you need the DbSet constaint for the implementation, you should add it to the interface:
void Add<T>(T entity) where T : DbSet;