I have the following classes:
// -- model hierarchy
public interface IJob {
}
public abstract class AbstractJob : IJob {
}
public class FullTimeJob : AbstractJob {
}
// -- dao hierarchy
public interface IJobDao<T> where T : IJob {
T findById(long jobId);
long insert(T job);
}
public interface IFullTimeJobDao : IJobDao<FullTimeJob> {
}
public abstract class AbstractDao {
}
public abstract class AbstractJobDaoImpl<T> : AbstractDao, IJobDao<T> where T : IJob {
public T findById(long jobId) {
// omitted for brevity
}
public long insert(T job) {
// omitted for brevity
}
}
public class FullTimeJobDaoImpl : AbstractJobDaoImpl<FullTimeJob>, IFullTimeJobDao {
}
I'm calling the following code from a factory method, which does not seem to work:
public IJobDao<IJob> createJobDao(long jobDaoTypeId)
{
object jobDao = Activator.CreateInstance(typeof(FullTimeJobDaoImpl));
return jobDao as IJobDao<IJob>; // <-- this returns null
return (IJobDao<IJob>) jobDao; // <-- this cast fails
}
How is this "up cast" properly achieved?
Make IJobDao interface covariant:
public interface IJobDao<out T> where T : IJob
{
T findById(long jobId);
}
Update:
You cannot have interface methods both returning and accepting generic values and make it covariant at the same time.
Possible solutions:
create a non-generic version of IJobDao<T> - IJobDao (of course, you'll have to implement both interfaces in classes, implementing IJobDao<T>)
split IJobDao<T> into 2 interfaces (one covariant and one contravariant)
consider a solution with only non-generic interface IJobDao (you are not getting any type-safety here anyway, which is the main purpose of generics)
Some ideas on implementing first scenario:
public interface IJobDao
{
IJob findById(long jobId);
long insert(IJob job);
}
public interface IJobDao<T> : IJobDao
where T : IJob
{
new T findById(long jobId);
new long insert(T job);
}
public abstract class JobDaoBase<T> : IJobDao<T>, IJobDao
where T : IJob
{
public abstract T findById(long jobId);
public abstract long insert(T job);
IJob IJobDao.findById(long jobId)
{
return findById(jobId);
}
long IJobDao.insert(IJob job)
{
return insert((T)job);
}
}
public class FullTimeJobDaoImpl : JobDaoBase<FullTimeJob>
{
public override FullTimeJob findById(long jobId)
{
// implementation
}
public override long insert(FullTimeJob job)
{
// implementation
}
}
// we are still unable to return generic interface, but we don't need to.
public static IJobDao createJobDao(/* my params */)
{
object jobDao = Activator.CreateInstance(typeof(FullTimeJobDaoImpl));
return jobDao as IJobDao;
}
For this cast to be possible you'll need to mark the interface type parameter as out:
public interface IJobDao<out T> where T : IJob {...}
Then
object jobDao = Activator.CreateInstance(typeof(FullTimeJobDaoImpl));
var r = jobDao as IJobDao<IJob>; //not null
But this brings some restrictions on the interface. Read out (Generic Modifier) (C# Reference) for more info.
In a generic interface, a type parameter can be declared covariant if
it satisfies the following conditions:
The type parameter is used only as a return type of interface methods and not used as a type of method arguments.
The type parameter is not used as a generic constraint for the interface methods.
Consider using Inversion of Control approach with a container. The various implementations register themselves in the container. The resolver enquires please an instance of (x).
See Unity as 1 of many IOC Container tools.
Related
I want to cast the type of the interface definition in the C# implementation.
ex):
public interface IModel
{
IModel Apply(IModel from);
}
public class XxxModel: IModel
{
public XxxModel Apply(XxxModel from) // <- Interface Implementation Error
{
}
}
As a Countermeasure:
public class XxxModel: IModel
{
public IModel Apply(IModel from)
{
if (from.GetType() != typeof(XxxModel))
throw new ArgumentException("Type Not Matched.");
...
}
}
However, this leaves open the possibility of errors during execution.
I want to make the types of the argument and return value an implementation class.
What would be the best way?
You can create a generic interface, using the implementation class for its generic type:
public interface IModel<T> where T: IModel<T>
{
T Apply(T from);
}
public class XxxModel: IModel<XxxModel>
{
public XxxModel Apply(XxxModel from) // All good
{
}
}
I have the following interface hierarchy:
public interface IActor { ... }
public interface IHealthUser : IActor { ... }
and a third interface:
public interface IAction { void Perform(IActor caster) }
Why is the following not legal and can I get around it somehow?
public class HealthPotion : IAction
{
public void Perform(IHealthUser caster) { ... }
}
The contract defined by IAction states that you can Perform the action on any IActor. Any IActor. Not only IHealthUser. What your HealthPotion tries to do is only implement a subset of IAction, meaning to perform its task only on a subset of IActors. That's not what the IAction interface states.
If you want a specific IAction to be able to restrict the type of IActor it applies to, you can do it using generic constraints:
public interface IAction<TAppliesTo> where TAppliesTo : IActor
{
void Perform(TAppliesTo appliesTo);
}
public class UniversalAction : IAction<IActor>
{
public void Perform (IActor anyone) {}
}
public class HealthPotion : IAction<IHealthUser>
{
public void Perform (IHealthUser healthUserOnly){}
}
You need to implement the same signature as your interface defines. You are using IActor in the interface but then you are using IHealthUser in the implementation of IAction interface. You should implement the Perform with the IActor parameter. It can be called however with class that implements IHealthUser.
Maybe this is a dumb question. But, I don't get the point what I am missing.
Given the following class-definition
public abstract class AbstractBaseClass
{
public abstract void Create(AnotherAbstractClass param1);
}
Wheras AnotherAbstractClass is defined
public abstract class AnotherAbstractClass
{
}
with a concrete implementation
public class AnotherConcreteImplementation : AnotherAbstractClass
{
}
I want to be able to have the override of the Create method to use a concrete type:
public class ConcreteImplementation : AbstractBaseClass
{
public override void Create(AnotherConcreteImplementation param1) <-- There is no suitable method for override
{
// param1 is an instance of the concrete implementation
}
public override void Create(AnotherAbstractClass param1) <-- this is working but I'll have to cast on each implementation
{
// param1 is an instance of the abstract class and needs a cast
}
}
Is this simply not possible or is there some way I'm not aware of? Maybe using generics?
Edit #1 (added more context)
I'm trying to achieve/enforce that in a concrete implementation there is only one parameter valid.
Think of it like it's a database-layer. The Create method will create a new entry in the database. As of each table has different values, the create-parameter also has.
The casting inside smells (in my opinion) as of it can be called with any concrete implementation of AnotherAbstractClass.
public class AddressTable : AbstractBaseClass
{
public override void Create(AnotherAbstractClass param1)
{
// cast to concrete instance
var casted = (ConcreteAddressCreate)param1;
}
}
public class CityTable : AbstractBaseClass
{
public override void Create(AnotherAbstractClass param1)
{
// cast to concrete instance
var casted = (ConcreteCityCreate)param1;
}
}
Having an instance of AddressTable I can call
addressIntance.Create(new ConcreteAddressCreate()); // would be okay
on the other hand I can call it
addressIntance.Create(new ConcreteCityCreate()); // would be okay but will fail at runtime with InvalidCastException
Edit #2 (additional info)
It should also be possible to extend the AbstractBaseClass class with more abstract methods later.
So, for me it's more likely to have generic methods instead of an concrete class-implemenation with 200 generic parameters for each method to implement.
It violates the Liskov Substitution Principle so it makes perfect sense you can't do this. Namely, you can't just "have" covariance like this for free:
AbstractBaseClass bcl = new ConcreteImplementation();
bcl.Create(new DifferentImplementationWithoutSecondAbstract());
The contract AbstractBaseClass defines makes Create have to work with any implementation of AbstractBaseClass passed in - if you give a constraint on what can be passed in you've violated the contract it defines.
Like you assumed - you can use generics:
// notice the recursive definition, we require the generic parameter
// to be a generic parameter of itself - allowing AbstractBaseClass
// to not be aware of its subclasses like in the other answers.
public abstract class AbstractBaseClass<T> where T : AbstractBaseClass<T>
{
public abstract void Create(T param1);
}
public class Concrete : AbstractBaseClass<Concrete>
{
public override void Create(Concrete param1)
{
Console.WriteLine("Hello!");
}
}
Yes, you can do that using generics:
public abstract class AbstractBaseClass<T>
where T : AnotherAbstractClass
{
public abstract void Create(T param1);
}
public class ConcreteImplementation : AbstractBaseClass<AnotherConcreteImplementation>
{
public override void Create(AnotherConcreteImplementation param1)
{
}
}
Generics is indeed the way to do it.
public abstract class AbstractBaseClass<TDerivedClass> where TDerivedClass : AnotherAbstractClass
{
public abstract void Create(TDerivedClass param1);
}
And then you can do:
public class ConcreteImplementation : AbstractBaseClass<AnotherConcreteImplementation>
{
public override void Create(AnotherConcreteImplementation param1) // Works because TDerivedClass = AnotherConcreteImplementation
{
...
}
}
I don't know whether I'm approaching this from the right angle or not, but either way I can't find syntax that works.
I want to pass 3 generic types to a method - from there I'll use reflection to create objects when I need them. However the object I'm passing is itself generic.
It sort of sounds like nested generics.
Let's say I create an interface:
public interface IAgent<TRequest, TClient, TResponse>
{
}
I have a class like this that implements IAgent:
public class MyClass : IAgent<?>
Then I want to call a method something like this:
public method MyMethod<T>(T obj) where T : IAgent<?>
{
// do somethings here
}
UPDATE
Here's what I currently do at class level.
public sealed class T3Agent
: AppAgent<T3RequestAdapter, T3WebClient, T3ResponseAdapter>
{
}
public abstract class AppAgent<TRequest, TClient, TResponse>
where TRequest : IAgentRequestAdapter
where TClient : CustomWebClient
where TResponse : IAgentResponseAdapter
{
public AppResponse Submit(IAppForm appForm, ServiceLog log)
{
}
}
public sealed class AppManager
{
public AppResponse Submit()
{
var t3 = new T3Agent();
var t3Result = t3.Submit(Form, Log);
return t3Result;
}
}
In the final method, I instantiate a new class (T3Agent), but this is tightly coupled to T3. I want to be able to instantiate AppAgent once and pass the required generic types through the method rather than the class, so that I can reuse the class.
I think you have 2 options:
if you have to work with generic class T from Agent<T> you have to know the type anyway so you have to put it in your generic declaration (see TypeNeeded() method below)
If it is not necessary, then split up the interface in a not generic and in a generic interface and then let IAgent<T> extend IAgent (IAgent<T>: IAgent). Now you can create a method without to know the type for IAgent<T> (see method DoSomething())
public interface IAgent
{
void Action( );
int Calculate( );
}
public interface IAgent< T > : IAgent
{
void Set( T value );
}
public class MyClass
{
public void DoSomething< T >( T agent ) where T : IAgent
{
//...
}
public void TypeNeeded< T, V >( T agent ) where T : IAgent<V>
{
}
}
If you don't know the types for your generic interface yet, your class or method needs to be generic, too:
public class MyClass<TRequest, TClient, TResponse> : IAgent<TRequest, TClient, TResponse>
{
}
Or for the method:
public void MyMethod<T, TRequest, TClient, TResponse>(T obj) where T : IAgent<TRequest, TClient, TResponse>
{
// do somethings here
}
public enum RepositoryType
{
ClinicRepository,
MedicationRepository,
PatientRepository,
TreatmentRepository
}
public class ObjectFactory<T>
{
public static IRepository<T> GetRepositoryInstance(RepositoryType type)
{
switch (type)
{
case RepositoryType.ClinicRepository:
return new what ?;
default:
return what ?
}
}
}
public interface IRepository<T>
{
void Add(T item);
void Remove(int id);
void Update(T item);
IList<T> GetAll();
T GetItemById(int id);
}
I'm trying to create a RepositoryFactory class and I copied what I've done so far. Could anyone please help me to figure this out ? I'm stuck !
Thanks in advance
edit :
I want something like this at the end. Is it possible to make 1 Repository class and implement something like
dc.THATOBJECT.insertonsubmit(item) ?
public class TreatmentRepository : IRepository<Treatment>
{
public void Add(Treatment item)
{
using (PatientsDataContext dc = new PatientsDataContext())
{
dc.Treatments.InsertOnSubmit(item);
dc.SubmitChanges();
}
}
The simplest of factories just requires that your types derived from IRepository have parameterless constructors.
public class ObjectFactory {
public static TRepository GetRepositoryInstance<T, TRepository>()
where TRepository : IRepository<T>, new() {
return new TRepository();
}
}
If you require specific constructors for a given repository type, you can specify the objects as an object array and create them using CreateInstance
public class ObjectFactory {
public static TRepository GetRepositoryInstance<T, TRepository>(
params object[] args)
where TRepository : IRepository<T> {
return (TRepository)Activator.CreateInstance(typeof(TRepository), args);
}
}
To use either of these, you just need to say
var treatmentRepo =
ObjectFactory.GetRepositoryInstance<Treatment, TreatmentRepository>();
To have something to return, you need to write a class that implements IRepository<T>.
public class SomeKindOfRepository<T> : IRepository<T>
{
public void Add(T item)
{
}
// and so on...
}
It appears there are four broad types (ClinicRepository, MedicationRepository, etc.) - are they very different in how they "store" things? If so, make a separate class for each one. Otherwise use the same class with some fields to control its behaviour.
Update
Based on your edits and comments, you have a repository that is really some operations on a table. The only thing that really varies is which table it wraps around. But the table is a member of a data context. So you could defer the choice of table to a derived class.
This would be the base class:
public class GeneralRepository<TEntity, TContext> : IRepository<TEntity>
{
protected abstract Table<TEntity> GetTable(TContext dc);
public void Add(Treatment item)
{
using (TContext dc = new TContext())
{
GetTable(dc).InsertOnSubmit(item);
dc.SubmitChanges();
}
}
// and so on for other methods
}
A derived class would only have to specify how to select a table from the context:
public class TreatmentsRepository : GeneralRepository<Treatment, PatientsDataContext>
{
protected override Table<Treatment> GetTable(PatientsDataContext dc)
{
return dc.Treatments;
}
}
You can do without the enum. You either need a generic repository type, or different repository types implementing IRepository<T>. If you use a generic repository, you can implement the factory by doing something along the lines of:
public class ObjectFactory<T>
{
public static IRepository<T> GetRepositoryInstance()
{
return new Repository<T>();
}
}
I would recommend that you use an Inversion of Control (IoC) container for this. In the Factory (or you could even go straight to the IoC container), could get the type.
public interface IClinicRepository : IRepository<Clinic> {}
public class ObjectFactory
{
public static IRepository<T> GetRepository(RepositoryType type)
{
switch (type)
{
case RepositoryType.ClinicRepository:
return container.Resolve<IClinicRepository>()
default:
throw new NotSupportedException()
}
}
}
or better yet Just use a generic method in your factory
public static IRepository<T> GetRepository<T>()
{
return container.Resolve<T>()
}
// to call it
var repository = ObjectFactory.GetRepository<IClinicRepository>();