Let's say I have a class library that defines a couple entity interfaces:
public interface ISomeEntity { /* ... */ }
public interface ISomeOtherEntity { /* ... */ }
This library also defines an IRepository interface:
public interface IRepository<TEntity> { /* ... */ }
And finally, the library has an abstract class called RepositorySourceBase (see below), which the main project needs to implement. The goal of this class is to allow the base class to grab new Repository objects at runtime. Because certain repositories are needed (in this example a repository for ISomeEntity and ISomeOtherEntity), I'm trying to write generic overloads of the GetNew<TEntity>() method.
The following implementation doesn't compile (the second GetNew() method gets flagged as "already defined" even though the where clause is different), but it gets at what I'm trying to accomplish:
public abstract class RepositorySourceBase // This doesn't work!
{
public abstract Repository<TEntity> GetNew<TEntity>()
where TEntity : SomeEntity;
public abstract Repository<TEntity> GetNew<TEntity>()
where TEntity : SomeOtherEntity;
}
The intended usage of this class would be something like this:
public class RepositorySourceTester
{
public RepositorySourceTester(RepositorySourceBase repositorySource)
{
var someRepository = repositorySource.GetNew<ISomeEntity>();
var someOtherRepository = repositorySource.GetNew<ISomeOtherEntity>();
}
}
Meanwhile, over in my main project (which references the library project), I have implementations of ISomeEntity and ISomeOtherEntity:
public class SomeEntity : ISomeEntity { /* ... */ }
public class SomeOtherEntity : ISomeOtherEntity { /* ... */ }
The main project also has an implementation for IRepository<TEntity>:
public class Repository<TEntity> : IRepository<TEntity>
{
public Repository(string message) { }
}
And most importantly, it has an implementation of the abstract RepositorySourceBase:
public class RepositorySource : RepositorySourceBase
{
public override IRepository<ISomeEntity> GetNew()
{
return new (IRepository<ISomeEntity>)Repository<SomeEntity>(
"stuff only I know");
}
public override IRepository<ISomeOtherEntity> GetNew()
{
return new (IRepository<ISomeEntity>)Repository<SomeOtherEntity>(
"other stuff only I know");
}
}
Just as with RepositorySourceBase, the second GetNew() method gets flagged as "already defined".
So, C# basically thinks I'm repeating the same method because there's no way to distinguish the methods from their parameters alone, but if you look at my usage example, it seems like I should be able to distinguish which GetNew() I want from the generic type parameter, e.g, <ISomeEntity> or <ISomeOtherEntity>).
What do I need to do to get this to work?
Update
I ended up solving this using specifically-named methods and a Func<T, TResult> parameter.
So, RepositorySourceBase now looks like this:
public abstract class RepositorySourceBase
{
public abstract Repository<ISomeEntity> GetNewSomeEntity();
public abstract Repository<ISomeOtherEntity> GetNewSomeOtherEntity();
}
And RepositorySource looks like this:
public class RepositorySource : RepositorySourceBase
{
public override IRepository<ISomeEntity> GetNewSomeEntity()
{
return new (IRepository<ISomeEntity>)Repository<SomeEntity>(
"stuff only I know");
}
public override IRepository<ISomeOtherEntity> GetNewSomeOtherEntity()
{
return new (IRepository<ISomeEntity>)Repository<SomeOtherEntity>(
"other stuff only I know");
}
}
Now, what started this whole thing off was that I needed a generic RepositoryUtilizer class that could grab a repository from a source simply by knowing the type of repository (which could be specified as a generic type parameter). Turns out, that wasn't possible (or at least not easily possible). However, what is possible is to use the Func<T, TResult> delegate as a parameter to allow the RepositoryUtilizer class to obtain the repository without needing to "know" the method name.
Here's an example:
public class RepositoryUtilizer
{
public DoSomethingWithRepository<TEntity>(
Func<TRepositorySource, IRepository<TEntity>> repositoryGetter)
{
using (var repository = repositoryGetter(RepositorySource))
{
return repository.DoSomething();
}
}
}
}
You cannot get this work as you intended. Type constraints cannot be used to decide between your two methods.
public abstract Repository<TEntity> GetNew<TEntity>()
where TEntity : SomeEntity;
public abstract Repository<TEntity> GetNew<TEntity>()
where TEntity : SomeOtherEntity;
Assume
public class SomeEntity { }
public class SomeOtherEntity : SomeEntity { }
and SomeOtherEntity is a valid type argument for both methods yielding two methods with identical signature.
The way to go is probably a single generic method that uses the supplied type argument to dispatch the call to the desired implementation. This is in turn probably solved most easily by implementing an interface on all concrete types.
Constraints are not part of the signature. This fact has numerous ramifications, many of which apparently irk people to no end. For some of those ramifications, and about a million comments telling me that I am WRONG WRONG WRONG, see this article and its accompanying comments.
http://blogs.msdn.com/ericlippert/archive/2009/12/10/constraints-are-not-part-of-the-signature.aspx
I would solve your problem by having two methods with two different names.
The only solution I can think of is to define an IRepositorySource<T> interface that each RepositorySource class can implement explicitly:
public interface IRepositorySource<T>
{
IRepository<T> GetNew();
}
public class RepositorySource : IRepositorySource<ISomeEntity>, IRepositorySource<ISomeOtherEntity>
{
IRepository<ISomeEntity> IRepositorySource<ISomeEntity>.GetNew()
{
...
}
IRepository<ISomeOtherEntity> IRepositorySource<ISomeOtherEntity>.GetNew()
{
...
}
}
To access these methods you'll need to cast a RepositorySource instance into the required interface type e.g.
IRepository<IEntity> r = ((IRepositorySource<IEntity>)repositorySource).GetNew();
public class RepositorySource
{
static IRepository<T> IRepositorySource.GetNew<T>()
{
if (typeof(T) == typeof(ISomeEntity))
return (IRepository<T>)new SomeEntityRepository();
...
}
}
Related
ok I'm little lost with generics in C#
I have this generic interface
interface IInvoiceStorage<T>
where T : class
{
void Persist(T Invoice);
}
with two classes implementing the interface
public class FacturaStorageForSQLServer:IInvoiceStorage<EVT>
{
public void Persist(EVT Invoice)
{
/*Implementation*/
}
}
public class FacturaStorageForMySQLServer:IInvoiceStorage<EVTFruit>
{
public void Persist(EVTFruit Invoice)
{
/*Implementation*/
}
}
The problem comes when I want to declare this in my service class
public class invoice_service
{
IInvoiceStorage Storage;
public invoice_service(IInvoiceStorage storage)
{
Storage=_storage;
}
}
C# tells me that I have to declare de type of the interface but if I do that then my service class is going to depend from the implementation and not from the interface.
Suggestions??
UPDATE 1:
Sorry If I declare the type the interface is going to depend only from the implementations using that type but what happens if I have two implementations using two different types for example EVT and EVTFruit.
I was thinking to use another interface to establish a relationship between EVT and EVTFruit but they can be two totally different objects so I'm not sure if it is a good idea.
You could change your class a little bit:
public class invoice_service<T> where T : class
{
IInvoiceStorage<T> Storage;
public invoice_service(IInvoiceStorage<T> storage)
{
Storage=_storage;
}
}
Which would allow you to use the interface correctly and keep it generic.
Depending on your needs, you could also defined non-generic version of that interface:
public interface IInvoiceStorage
{
...
}
And make classes inherit from this interface, too.
public class FacturaStorageForSQLServer : IInvoiceStorage, IInvoiceStorage<EVT>
public class FacturaStorageForMySQLServer : IInvoiceStorage, IInvoiceStorage<EVTFruit>
That way you can use non-generic version of interface in invoice_service class.
But, as I said, depending on your needs if you can make functionality of that interface independent of type (for example, List<T> also implements IList for list functionalities, without type).
After trying your suggestions and reading some blogs here is what I did and is fulfilling my requeriments at least for now. The problem was resolved when I realized that I shouldn't use the generic repository pattern as a repository itself but as a helper of the repository! At the end what I'm doing is wrapping the generic interfaces inside of another layer of non-generic interfaces.
a Service class calling for an IInvoiceRepositoryService implementation
public class InvoiceService
{
private IInvoiceRepositoryService RepositoryService;
public SQLInvoiceService(IInvoiceRepositoryService _RS)
{
RepositoryService=_RS;
}
}
and their respective implementation for EVT and EVTFruit.
public class EVTRepository:IInvoiceRepositoryService
{
private IInvoiceStorage<EVT> EVTStorage;
public EVTInvoiceRepository(IInvoice<EVT> _EVT)
{
EVTStorage=_EVT;
}
}
public class EVTStorageForSQLServer: IInvoiceStorage<EVT>
{
/*Implementation*/
}
public class EVTStorageForMySQLServer: IInvoiceStorage<EVT>
{
/*Implementation*/
}
public class EVTFruitRepository:IInvoiceRepositoryService
{
private IInvoiceStorage<EVT> EVTFruitStorage;
public EVTFruitInvoiceRepository(IInvoice<EVTFruit> _EVTFruit)
{
EVTFruitStorage=_EVTFruit;
}
}
public class EVTFruitStorageForSQLServer: IInvoiceStorage<EVTFruit>
{
/*Implementation*/
}
public class EVTFruitStorageForMySQLServer: IInvoiceStorage<EVTFruit>
{
/*Implementation*/
}
At the end this was just a design problem I think. I'm going to mark Ron Beyer's response as the answer because is valid and it was really straightforward
I have an abstract class but and 6 different implementations of it. Now for one of them I would like to add an extra public method but would not like to add it to the abstract class because the other 5 implementations don't need it.
Is there a way of implementing this? I am getting an error when I add this new method without it being in the abstract class.
Here is the code:
namespace Results.Parser
{
public abstract class Parser<T> where T: ReportItem
{
public abstract string GetNodeName();
public abstract IEnumerable<ReportItem> ParseXml(TextReader stream);
public abstract List<ReportItem> SumValueOfDuplicateRows(List<T> reportList);
public virtual bool MeetsCriteria(ReportItem reportItem)
{
return reportItem.Value.SafeConvertToDecimal() != 0;
}
}
}
public class ElementParser : Parser<ReportItem>
{
public override string GetNodeName()
{
return "Element";
}
public override List<ReportItem> SumRiskValueOfDuplicateRows(List<ReportItem> reportList)
{
// do something
}
public void SerializeXml(TextReader stream)
{
//new method which is not in abstract class
}
public override IEnumerable<ReportItem> ParseXml(TextReader stream)
{
//do something
}
}
namespace Results.Producer
{
public class RepositoryManager
{
private void GetResponse(TextReader stream)
{
var parser = new ElementParser();
parser.SerializeXml(stream);
}
}
I am getting an error when I add this new method without it being in the abstract class.
A superclass reference to a subclass instance can't access methods not defined in the super class. You will need to explicitly cast your reference to a subclass reference type to be able to access the extra method from the subclass.
Let A be the abstract class and let B be the class where you have an extra method called extra. Let a be a reference of type A to an instance of type B. To access the extra method in B, do this :
((B)a).extra();
That being said, if only one of the classes needs additional behavior that is different, you should consider using composition over inheritance. See this answer that explains the famous duck problem that is similar to the situtation you are in currently
I have the following "models":
My base class:
public abstract class Search : Model
{
//Properties ...
public void ShallowCopy(Search reference)
{
base.ShallowCopy(reference);
//Do stuff
}
}
My inheriting class:
public class Vehicle : Search
{
//Properties
public void ShallowCopy(Vehicle reference)
{
base.ShallowCopy(reference);
//Do stuff
}
}
My base "viewModel" is generic:
public abstract class MasterDataWithoutAddressViewModel<TPrimaryModel> : MasterDataViewModel<TPrimaryModel>
where TPrimaryModel : Search, new()
{
public void JustAMethod()
{
//do stuff
foreach (TPrimaryModel primaryModel in primaryModels)
{
TPrimaryModel primaryModelCopy = new TPrimaryModel();
primaryModelCopy.ShallowCopy(primaryModel);
//Do more stuff
}
}
}
My inheriting "viewModel":
public class VehicleViewModel : MasterDataWithoutAddressViewModel<Vehicle>
{
//...
}
With primaryModelCopy.ShallowCopy(primaryModel); I expected the ShallowCopy of Vehicle to be called. However just the method of the base class Search is called. Debugger shows that primaryModel and primaryModelCopy are both from the correct type (Vehicle).
This is the complete inheritance hierarchy of my "models":
This happens because you have a compile time collision (due to the way overload resolution behaves) between methods with the same signature in your base and derived classes.
You need to declare your method virtual, and override them in derived classes:
Base:
public virtual void ShallowCopy(Search reference)
{
base.ShallowCopy(reference);
//Do stuff
}
Derived:
public override void ShallowCopy(Search reference)
{
base.ShallowCopy(reference);
//Do stuff
}
Overload resolution is performed at compile-time, and in JustAMethod it's performed once, not once per type-argument. So primaryModelCopy.ShallowCopy is resolved to the Search.ShallowCopy method.
There are two options here:
You could use normal polymorphism, making Search.ShallowCopy virtual, and overriding it in Vehicle.ShallowCopy (which would need to cast the parameter back to Vehicle in the method)
You could use dynamic typing in JustAMethod to perform overload resolution at execution-time instead. (This doesn't feel like a good idea to me, but it's an option.)
Given these base classes and interfaces
public abstract class Statistic : Entity, IStatistic
{
protected abstract IStatisticsRepository<IStatistic> Repository {get;}
...
public class AverageCheckTime : Statistic
...
public interface IStatisticsRepository<T> : IRepository<T> where T : IStatistic
...
public interface IAverageCheckTimeRepository : IStatisticsRepository<AverageCheckTime>
...
public class AverageCheckTimeRepository : StatisticRepository<AverageCheckTime>, IAverageCheckTimeRepository
...
public class RepositoryFactory
{
public static IAverageQueueTimeRepository AverageQueueTimeRepository
{
get { return CurrentServiceLocator.GetInstance<IAverageQueueTimeRepository>(); }
}
Why does AverageCheckTime's implementation throw an invalid cast exception:
protected override IStatisticsRepository<IStatistic> Repository
{
get { return (IStatisticsRepository<IStatistic>)RepositoryFactory.AverageCheckTimeRepository; }
}
How do I cast an instance of IAverageCheckTimeRepository as an IStatisticsRepository<IStatistic> which I assumed it already was?
OK, I've made these changes...which makes me wonder if I've gone over the top with the generics in the first place
public interface IStatisticsHelper
{
void GenerateStatistics();
List<IStatistic> BuildReport();
}
...
public interface IStatisticsRepository<T> : IRepository<T>, IStatisticsHelper where T : IStatistic
{
}
...
public abstract class Statistic : Entity, IStatistic
{
protected abstract IStatisticsHelper Repository { get; }
...
public class AverageCheckTime : Statistic
{
protected override IStatisticsHelper Repository
{
get { return RepositoryFactory.AverageCheckTimeRepository; }
}
No, C# 3 does not support generic variance. C# 4 does, but you would have to declare that IStatisticsRepository is covariant in T:
public interface IStatististicsRepository<out T> : IRepository<T>
where T : IStastistic
Variance isn't safe in general - it depends on how the generic type parameter is used. C# 4 supports both covariance and contravariance for type arguments which are reference types, but only when the generic type involved is an interface or a delegate, and only when the type parameter is used in the appropriate way within the interface/delegate.
Without seeing the declaration for IRepository<T>, we can't tell whether or not it's safe. For example, if IRepository<T> contains a method like this:
void Save(string id, T value);
then it wouldn't be safe, because you'd be able to write:
IStatisticsRepository<IStatistic> repo = RepositoryFactory.AverageCheckTimeRepository;
IStatistic foo = new SomeOtherStastisticType();
repo.Save("Foo", foo);
That would be trying to save a SomeOtherStatisticType value in an AverageCheckTimeRepository, which violates type safety. It's only safe to make the interface covariant in T if values of type T only come "out" of the interface. (There are some wrinkles around exactly what that means, mind you...)
For a lot more information on this, see Eric Lippert's blog series on the topic.
I have a class similar to the following:
public abstract class Manager<T, TInterface> : IManager<T> where TInterface : IRepository<T>
{
protected abstract TInterface Repository { get; }
public virtual List<T> GetAll()
{
return Repository.GetAll();
}
}
This works perfectly fine, however, is there a way to get away from having the TInterface in the abstract class declaration and in the resulting class that extends my generic abstract class:
public class TestManager : Manager<TestObject, ITestRepository>, ITestManager
I am forced to use ITestRepository and make the Repository property abstract due to the fact that it can contain custom methods that I need to know about and be able to call.
As I continue to build layers, I will have to keep doing this process the whole way up the stack. Examples would be if I had a generic abstract controller or service layer:
public class TestService : Service<TestObject, ITestManager>, ITestService
Is there a better way to do this or is this the best practice to allow a generic class to call another generic class?
It seems that all you want to do is to make Manager<T> testable, and use a mock as a repository that you can query for special members.
If that's the case, maybe you can change your design to this:
public class Manager<T> : IManager<T> {
protected IRepository<T> Repository { get; set; }
// ...
public virtual List<T> GetAll() {
return Repository.GetAll();
}
}
Now, all the specifics of testing are in a testing subclass:
public class TestingManager<T> : Manager<T> {
public new ITestRepository<T> Repository {
get {
return (ITestRepository<T>)base.Repository;
}
set {
base.Repository = value;
}
}
}
When you write your unit tests, you create TestingManager<T> instances (referenced through TestingManager<T> declared variables and fields), and you provide them with a test repository. Whenever you query their Repository, you'll always get a strongly-typed test repository.
UPDATE:
There's another way to solve this, without a subclass. You declare your repository objects as test repositories that you pass to Manager<T>s and you query them directly, without going through the Manager<T>.
[Test]
public void GetAll_Should_Call_GetAll_On_Repository_Test() {
var testRepository = new TestRepository();
var orderManager = new Manager<Order>(testRepository);
// test an orderManager method
orderManager.GetAll();
// use testRepository to verify (sense) that the orderManager method worked
Assert.IsTrue(testRepository.GetAllCalled);
}
No, you can't get around it. You can try, but the result will be ugly and in some way incorrect. The reason is that you are asking generics not to be generic but still be generic.
If a new class uses a generic class, either in inheritance or composition, and it itself does not know enough to specify the type parameters to the generic class it is using, then it must itself be generic. It is analogous the method call chains, where a method may pass parameters along to another method. It can't make up the arguments to the inner method, but must rather take them as parameters itself from a caller that does know what they are. Type parameters are the same.
One thing that does make this feel like code smell is the fact that you can't have a variable of type Manager<,>. It has to be fully type-specified. One solution I've come up with is to have non-generic interfaces that the generic classes implement. These interfaces have as much of the public interface of the generic class as is possible (they can't have methods or properties that reference the type parameters). Then you can pass around variables of the type of the interface and not have to specify type parameters.
Example:
interface IExample {
string Name { get; }
void SomeNonGenericMethod(int i);
}
class Example<T> : IExample {
public string Name { get { ... } }
public void SomeNonGenericMethod(int i) {
...
}
public T SomeGenericMethod() {
...
}
}