Generic base class constructor - c#

Using this generic base class:
public abstract class Logic<U> where U : class
{
protected U m_provider;
public Logic(U provider)
{
m_provider = provider;
}
}
I'm trying to create a base test class for unit test:
public class LogicBaseTest<T, U> where T : Logic <U>, new() where U: class
{
protected T m_logic;
protected U m_provider;
[OneTimeSetUp]
public virtual void OneTimeSetup()
{
m_provider = (U)Substitute.For<IInterface>();
m_logic = new T(m_provider);
}
}
It complains on the constructor, it requests for the new() constrain but when I add it then it complains that the constructor cannot take parameters.
I could add a method to populate the provider but I'm wondering whether it could be done in the constructor.

So you have two problems here:
LogicBaseTest needs to know how to instantiate a Logic<U>.
Logic<U> requires a U in the constructor.
My proposed solution to it is to pass a factory delegate into the base test class and remove the new() requirement. Then your setup can construct the Logic class using the factory:
public class LogicBaseTest<T, U>
where T : Logic<U>
where U: class
{
protected readonly Func<U, T> _factory;
public LogicBaseTest(Func<U, T> factory)
{
_factory = factory;
}
[OneTimeSetUp]
public virtual void OneTimeSetup()
{
m_provider = (U)Substitute.For<IInterface>();
m_logic = _factory(m_provider);
}
}
In the derived test class you just have to tell the base class how to new up a Logic<U>:
public class DerivedTest : LogicBaseTest<Logic<MyUType>, MyUType>
{
public DerivedTest()
: this(u => new Logic<MyUType>(u))
{
}
}

Let's break down your generic constraint into plain English
where T : Logic<U>, new()
This means
The type of T needs to inherit from Logic, the generic type parameter must be U and have a public, parameterless, constructor
But the problem is that Logic by itself already breaks that constraint. Now, how do we fix this? There are multiple ways
Use a "factory function" to instantiate your m_logic alongside removing the new constraint (see DiplomacyNotWar's answer)
Remove the new() constraint and use something like Activator.CreateInstance instead to instantiate your Logic class
Add a parameterless constructor to Logic and configure your m_provider some other way
Move instantiation of m_logic into the unit test itself (maybe add a helper method if you need to create the same Logic for a ton of unit tests)
Research if your unit testing framework supports some form of Dependency Injection and inject everything you need

You cannot add a generic type constraint such as where T : new(U).
Instead, you can use a Factory.
public interface IFactory<out TObject, in TProvider>
{
public TObject Create(TProvider provider);
}
then use it in your base test
public class LogicBaseTest<T, U> where T : Logic <U> where U: class // remove new()
{
// fields
private readonly IFactory<T, U> _factory;
public LogicBaseTest(IFactory<T, U> factory)
{
_factory = factory;
}
[OneTimeSetUp]
public virtual void OneTimeSetup()
{
m_provider = (U)Substitute.For<IInterface>();
m_logic = _factory.Create(m_provider);
}
}
Example
public class Logic1Provider
{
}
public class Logic1Factory : IFactory<Logic1, Logic1Provider>
{
public Logic1 Create(Logic1Provider provider)
{
return new Logic1(provider);
}
}
public class Logic1 : Logic<Logic1Provider>
{
public Logic1(Logic1Provider provider) : base(provider)
{
}
public void DoDomeLogic()
{
// do stuff
}
}
var factory = new Logic1Factory();
var baseTest = new LogicBaseTest<Logic1, Logic1Provider>(factory);

Related

Define which type will be used in a constructor

I would like to associate an object of type AbstractObject to my current Class.
However, this has to be done in the constructor, since, when I define my Class I don't know which type of object would be associated (only that this is of type AbstractObject). And I need to construct the associated object in my class (So I can't put an instance as parameter).
So it would be something like:
public abstract class MyClass
{
public MyClass(Type T) where T : AbstractObject
{
(T)Actiocator.CreateInstance(Typeof(T));
//To do
}
}
but this doesn't work. Any idea how to fix this?
Depending on your use case, there are several options.
Passing in the object
The simplest way is have the caller construct the object, and pass it in through the constructor:
public MyClass(AbstractObject template)
{
// Do something with template
}
Provide a static factory method
Expanding on the idea above, if you want to have control over the object that the constructor uses, you can provide a static method that creates a Base object and passes it to the constructor:
private MyClass(AbstractObject template)
{
// Do something with template
}
public MyClass Create<T>() where T : AbstractObject, new()
{
// Create a temporary object just for passing into the private ctor
return new MyClass(new T());
}
I made the constructor private so you can create a new MyClass object only through the static instance:
MyClass.Create<Concrete>();
Also note I added the new() constraint, so I can simply write new T. This is fine if you know that T is going to a be a derived class of AbstractObject which is a reference type. If you want to be able to construct MyClasses from value types such as int, you can drop the new() constraint and use reflection.
Make the class generic
If you also need to store the object in your class, make the whole class generic:
public class MyClass<T> where T : AbstractObject, new()
{
private T myObject;
public MyClass()
{
this.myObject = new T();
// Do other stuff
}
}
Create a interface or a abstract class them implement it in the class you want to pass into the current class constructor
public interface ITest
{
// your interface method and properties
}
public class Child : ITest
{
// do your stuff here
}
public abstract class MyClass
{
public MyClass(ITest tes)
{
// do stuff using test
}
}
maybe something like this would suit you?
abstract class AbstractObject {}
class Test : AbstractObject
{
public Test()
{
Console.WriteLine("I work");
}
}
class GenTest<T> where T: AbstractObject, new()
{
T obj;
public GenTest()
{
obj = new T();
}
}
public static void Main()
{
var genTestObj = new GenTest<Test>();
}
Try this:
public abstract class MyClass<T> where T : AbstractObject, new()
{
public MyClass(T type)
{
T instance = new T();
}
}
If you add new() in the generics constraints, you can call the parameterless constructor of your class.
https://msdn.microsoft.com/en-us/library/bb384067.aspx

How to pass generic in an interface (nested generics)

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
}

C# .NET 3.5 Get Generic Definition

I have the following class
public class AbstractJobDao<T> where T : IJob {
protected T buildJob() {
// create an IJob implementation instance based on the generic parameter
}
}
public class FullTimeJobDao : AbstractJobDao<FullTimeJob> {
}
public class InternshipDao : AbstractJobDao<Internship> {
}
Both FullTimeJob and Internship implement the IJob interface. I'd like the buildJob() method to be able to infer the generic in the Dao implementation class using reflection, and then create an instance of that type. Is there a way to do this using reflection in .NET 3.5?
If so, what should the line/lines of code look like in the buildJob() method?
EDIT -- I think I'm not clear on my question. What I want is for when buildJob() is called inside of the FullTimeJobDao, to create an instance of FullTimeJob. When buildJob() is called from inside of InternshipDao, it should create an instance of Internship, based on the generic type as defined at the top of the class.
What you have should almost work, except you don't require your generic argument to be instantiable. If you add that as a constraint, you should be able to use new:
public class AbstractJobDao<T> where T : IJob, new() {
protected T buildJob() {
return new T();
}
}
Alternatively, if you have some reason why that constraint is not appropriate in your situation, you can use Activator.CreateInstance:
public class AbstractJobDao<T> where T : IJob {
protected T buildJob() {
return Activator.CreateInstance<T>();
}
}
You have to declare your AbstractJobDao class this way :
public class AbstractJobDao<T> where T : IJob, new() {
protected T buildJob() {
return new T();
}
}
Note the new() after IJob : this way, you're indicating that parameter T :
Implements IJob's methods
Offers a constructor with no argument.
So the compiler will allow you to use new T().
You can create IJob factory to implement it
interface IJobFactory
{
IJob Create();
}
class FullTimeJobFactory
: IJobFactory
{
IJob Create()
{
return new FullTimeJob();
}
}
class InternshipJobFactory
: IJobFactory
{
IJob Create()
{
return new InternshipJob();
}
}
now you can use abstract factoy IJobFactory to create instancies of abstract IJob
public class AbstractJobDao<T> where T : IJob {
public AbstractJobDao(IJobFactory<T> factory)
{
}
protected IJobFactory<T> Factory{get;set;}
protected T buildJob() {
return Factory.Create();
}
}
public class FullTimeJobDao : AbstractJobDao<FullTimeJob> {
public FullTimeJobDao()
: base(new FullTimeJobFactory())
{}
}
public class InternshipDao : AbstractJobDao<Internship> {
public InternshipDao ()
: base(new InternshipJobFactory())
{}
}

Generic factories impossible when requiring dependency injection?

I am trying to make some generic factories for my service factories and dao factories and am running into some limitations.
Typically my service and dao factories look like this:
public static class PersonServiceFactory
{
private static PersonService personService;
public static PersonService GetInstance()
{
if (personService == null)
{
PersonDao personDao = PersonDaoFactory.GetInstance();
personService = new PersonService(personDao);
}
return personService;
}
}
public static class PersonDaoFactory
{
private static PersonDao personDao;
internal static PersonDao GetInstance()
{
if (personDao == null)
{
personDao = new PersonDao();
}
return personDao;
}
}
Then I tried doing a generic factories:
public abstract class EntityDaoFactory<daoClass>
where daoClass : class, new()
{
private static daoClass factorySupportClass;
internal static daoClass GetInstance()
{
if (factorySupportClass == null)
{
factorySupportClass = new daoClass();
}
return factorySupportClass;
}
}
public abstract class EntityServiceFactory<serviceClass, daoClass>
where serviceClass : class, new()
where daoClass : class
{
private static serviceClass factorySupportClass;
internal static serviceClass GetInstance()
{
if (factorySupportClass == null)
{
//daoClass daoSupportClass = *how to get daoSupportClassfactory.GetInstance(); here?*
factorySupportClass = new serviceClass(daoSupportClass);
}
return factorySupportClass;
}
}
So they could used like this:
public static class PersonDaoFactory : Entities.EntityDaoFactory<PersonDao>
{
}
public static class PersonServiceFactory : Entities.EntityServiceFactory<PersonService, PersonDaoFactory>
{
}
Here are the problems I am running into:
Can't use static class as type constraint for generics, which I was trying to use for the EntityServiceFactory, because without it I don't know how to inject the appropriate dao.
Can't have the factories derive from the Generic factories because I get an error like:
Static class 'Persons.PersonDaoFactory' cannot
derive from type
'Entities.EntityDaoFactory'.
Static classes must derive from object.
Tried making them all non-static classes with private constructors to get around that but then I get:
'Persons.PersonService' must be a non-abstract type with a public
parameterless constructor in order to use it as parameter
'serviceClass' in the generic type or method
'Entities.EntityServiceFactory
I was able to read why number 3 occurs on here, but that still doesn't solve my problems. I got the DaoFactory working, but it only works if the specific DaoClass doesn't need any dependency injection, otherwise error 3 pops up again.
Is there anyway to get these generic factories working using a different approach while still being able to use DI?
EDIT ----
I was able to get this sort of working, but it has some oddities. First I created a IEntityFactory interface:
public interface IEntityFactory<T>
where T : class
{
T GetInstance();
}
Then changed the EntityDaoFactory to:
public abstract class EntityDaoFactory<daoClass> : IEntityFactory<daoClass>
where daoClass : class, new()
{
private static daoClass factorySupportClass;
public daoClass GetInstance()
{
if (factorySupportClass == null)
{
factorySupportClass = new daoClass();
}
return factorySupportClass;
}
}
So I could pass in the appropriate type parameters and change the EntityServiceFactory to:
public abstract class EntityServiceFactory<serviceClass, daoClass, daoFactoryClass>
where serviceClass : class, new()
where daoClass : class, new()
where daoFactoryClass : IEntityFactory<daoClass>, new()
{
private static serviceClass factorySupportClass;
public static serviceClass GetInstance()
{
if (factorySupportClass == null)
{
daoFactoryClass daoSupportFactory = new daoFactoryClass();
daoClass daoSupportClass = daoSupportFactory.GetInstance();
factorySupportClass = new serviceClass();
}
return factorySupportClass;
}
}
So for a specific implementation such as with the Person object the calls look like:
public class PersonDaoFactory : Entities.EntityDaoFactory<PersonDao>
{
}
public class PersonServiceFactory : Entities.EntityServiceFactory<PersonService, PersonDao, PersonDaoFactory>
{
}
So it's working now, but the oddities are:
You can instantiate a factory, which was required (as far as I know the only way to do it?) for the EntityServiceFactory, but for someone using my API there would be no reason for them to do it but they still could.
Services and DAOs which have dependency requirements can now be instantiated with no parameters, which would break the instantiated class methods (but I had to do it to be able to use it as a type parameter). They shouldn't even ever by instantiating these objects anyway but they can now and do so incorrectly.
Also a final problem I just thought of is this solution doesn't really handle a variable amount of dependencies well. Still wonder if there is a better approach for this?
Conclusion: I think in the end even though it works, I gave up a lot of order to have that generic factory, which isn't that flexible and not giving me much, so I probably wouldn't use it in this case due to the limitations.
First of all, you are NOT using dependency injection. Depencency injection has nothing to do with providing type parameters to a generic class / method.
The errors occur because you are violating C#'s rules. You have to change your code to conform with them. So, make your classes non-static and do not use private constructors. You can replace a static class with a singleton instance and use protected constructors to avoid uncontroller instantiation.
I know that this question is really old, but I stumbled across it, so I figure I would give an answer.
The following compiles and does what you are looking to do:
public abstract class Entity<serviceFactory, serviceClass, daoFactory, daoClass>
where daoFactory : Entity<serviceFactory, serviceClass, daoFactory, daoClass>.DaoFactory, new()
where daoClass : class, new()
where serviceFactory : Entity<serviceFactory, serviceClass, daoFactory, daoClass>.ServiceFactory, new()
where serviceClass : class, new()
{
public abstract class DaoFactory
{
private static daoClass factorySupportClass;
internal static daoClass GetInstance()
{
if (factorySupportClass == null)
{
factorySupportClass = new daoFactory().createDao();
}
return factorySupportClass;
}
protected abstract daoClass createDao();
}
public abstract class ServiceFactory
{
private static serviceClass factorySupportClass;
internal static serviceClass GetInstance()
{
if (factorySupportClass == null)
{
daoClass daoSupportClass = DaoFactory.GetInstance();
factorySupportClass = new serviceFactory().createService(daoSupportClass);
}
return factorySupportClass;
}
protected abstract serviceClass createService(daoClass dao);
}
}
Now unless you are planning on using these types from within a composition root, I strongly recommend against doing the above solution since some of your dependencies are hidden and worse, are fixed to a limited set of parameters. Instead try something like this for a more DI/composition root friendly solution.

A Repository Factory Class

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>();

Categories