c# circular generic type parameters - c#

I have 2 generic classes: a ManagerBase class and a ChildBase class.
They're both abstract and are intended to be made concrete.
ManagerBase has a list of ChildBase, which is why I want to make it generic, so a CatalogManager : ManagerBase would have a list of Catalogs. Also, each Catalog would have reference to its' Manager - CatalogManager.
public class ManagerBase<T1> : ChildBase<???>
{
public ManagerBase()
{
ChildObjects = new List<T1>();
}
public List<T1> ChildObjects { get; set; }
}
public class ChildBase<T1> : ManagerBase<???>
{
public ChildBase(T1 parentMgr)
{
ParentMgr = parentMgr;
ParentMgr.ChildObjects.Add(this);
}
public T1 ParentMgr { get; set; }
}
How can I resolve this object model?
Thanks.

You have to define the base classes using the "curiously recursive" pattern:
public class ManagerBase<M, T1>
where M : ManagerBase<M, T1>
where T1 : ChildBase<M, T1>
{
public ManagerBase()
{
ChildObjects = new List<T1>();
}
public List<T1> ChildObjects { get; set; }
}
public class ChildBase<T1, C>
where T1 : ManagerBase<T1, C>
where C : ChildBase<T1, C>
{
public ChildBase(T1 parentMgr)
{
ParentMgr = parentMgr;
ParentMgr.ChildObjects.Add((C)(object)this);
}
public T1 ParentMgr { get; set; }
}
Please note I've stuck with your usage of T1, but I think that's a bit confusing. I would have preferred to have used M and C for each.
The major downside with this is that you have to use the nasty double cast of (C)(object)this to make this work. C# doesn't allow full type safety on this pattern. A nefarious developer can create child classes that can break the pattern.
Then the concrete classes can be this:
public class CatalogManager : ManagerBase<CatalogManager, Catalog>
{
}
public class Catalog : ChildBase<CatalogManager, Catalog>
{
public Catalog(CatalogManager parentMgr) : base(parentMgr)
{
}
}

Related

Covariance, generic, UserControl

I have created a user control that contains an ObservableCollection<Something>. I learned that I cannot cast say ObservableCollection<Tiger> to ObservableCollection<Animal>. The solution I found was to add a helper class that handles all low level collection manipulation. My suspicion is that there is a more elegant solution and if so, maybe someone can point me into that direction.
See the code below that captures the problem and my solution. Zoo corresponds to the WPF UserControl. (Actually a zoo for one type od animal.) Ideally I would define it as Zoo<T> i.e. as a generic type but that would prevent me from using XAML. I need to define Animals as object in order assign to it.
class Program
{
public static void Main(string[] args)
{
Zoo zoo = new Zoo();
List<Tiger> tigers = new List<Tiger>() { new Tiger() };
zoo.Animals = tigers;
zoo.Helper = new TigerHelper(tigers);
Console.WriteLine(zoo.GetCount());
Console.ReadLine();
}
}
public class Animal { }
public class Tiger : Animal { }
public interface Helper { int GetCount(); }
public class TigerHelper : Helper
{
private List<Tiger> tigers;
public TigerHelper(List<Tiger> tigers) { this.tigers = tigers; }
public int GetCount() { return tigers.Count; }
}
public class Zoo
{
public object Animals { get; set; }
public Helper Helper { get; set; }
public int GetCount() { return Helper.GetCount(); }
}
Rather than go all the way down to object, you can use IList. This gives you access to most of the features of the list, but without the generics. For example, you can still access the Count property:
public class Zoo
{
public IList Animals { get; set; }
public Helper Helper { get; set; }
public int GetCount() { return Animals.Count; }
}

c# inheriting from generic class

Let me describe the logic and then class structure. There are objects and all object must inherit from ConfigurationObjectBase. Each object must be owned by Manager and all Managers must be derived from ConfigurationObjectManagerBase. When a new instance of object created, one of the constructor must accept instance of Manager and that instance of Manager must add that instance of object into it's property called ChildObjects. Below is sample of classes. could you pls help to correct in below code acording above business rule? Thanks.
public class ConfigurationObjectBase<ObjectType>
{
public ConfigurationObjectBase(ConfigurationObjectManagerBase<ObjectType> ownerManager)
{
ownerManager.ChildObjects.Add(this);
}
}
public class ConfigurationObjectManagerBase<ObjectType>
{
public ConfigurationObjectManagerBase()
{
ChildObjects = new List<ObjectType>();
}
public List<ObjectType> ChildObjects { get; set; }
}
public class Catalog : ConfigurationObjectBase<Catalog>
{
public Catalog(CatalogManager ownerManager) : base(???)
{
}
}
public class CatalogManager : ConfigurationObjectManagerBase<CatalogManager>
{
public CatalogManager() : base()
{
}
}
There are two issues in your code:
CatalogManager should inherit from ConfigurationObjectManagerBase<Catalog>, not ConfigurationObjectManagerBase<CatalogManager>
ChildObjects should probably be a list of ConfigurationObjectBase<ObjectType>, rather than a list of ObjectType (otherwise you can't add a ConfigurationObjectBase<ObjectType> to it)
So the code should probably look like this:
public class ConfigurationObjectBase<ObjectType>
{
public ConfigurationObjectBase(ConfigurationObjectManagerBase<ObjectType> ownerManager)
{
ownerManager.ChildObjects.Add(this);
}
}
public class ConfigurationObjectManagerBase<ObjectType>
{
public ConfigurationObjectManagerBase()
{
ChildObjects = new List<ConfigurationObjectBase<ObjectType>>();
}
public List<ConfigurationObjectBase<ObjectType>> ChildObjects { get; set; }
}
public class Catalog : ConfigurationObjectBase<Catalog>
{
public Catalog(CatalogManager ownerManager) : base(ownerManager)
{
}
}
public class CatalogManager : ConfigurationObjectManagerBase<Catalog>
{
public CatalogManager()
{
}
}
Also, you don't need to call the default base class constructor (base()), it's done implicitly by the compiler.

Allow only types inherited from a Class

I have class A and B (just sample)
public class A
{
public long Id { get; set; }
public string Name { get; set; }
}
public class B : A
{
public B(long id,string name)
{
}
}
And want to do
var b = new B(100, "myName");
Save(b);
I have a save method that I want to allow only types inherited from A Class and also have uses the constructor that accept two parameters
// I know this will work if my Class B has public B() {},
//but not sure how to restrict to have only the once which accept constructor with two parameters
private void Save<T>(T target) where T : A, new ()
{
//do something
}
There's nothing in the C# type system that will enforce that constraint. You could use the reflection APIs to verify at runtime.
Another alternative would be to specify a factory:
interface IFactory<T> where T : A {
T Construct(object param1, object param2)
}
class BFactory : IFactory<B> {
public B Construct(object param1, object param2) {
return new B(param1, param2);
}
}
void Save<T>(T target, IFactory<T> tFactory) where T : A {
T newT = tFactory.Construct(a, b);
}
Generic constraints do not support constructors with parameters. Mostly a factory or creation function is used ( e.g. Is there a generic constructor with parameter constraint in C#? ), but since the object is created beforehand and you only want to filter which objects are allowed, a safer method is to implement an (empty) interface and use that as constraint:
public class A
{
public long Id { get; set; }
public string Name { get; set; }
}
public class B : A, IAmB
{
public B(long id,string name)
{
}
}
public interface IAmB{}
That way the constraint would be:
private void Save<T>(T target) where T : A, IAmB
{
}

C# Design Pattern - Best Way to Design For Many Datasources [duplicate]

This question already has answers here:
How to avoid Dependency Injection constructor madness?
(10 answers)
Closed 7 years ago.
I currently have an ASP.Net MVC 5 app that uses 3 external datasources (calls are made to external APIs, responses are deserialized, and mapped to business POCOs).
The app currently uses SimpleInjector to inject concrete repositories for each datasource into a business logic layer for consumption.
The problem is, as more datasources are added (potentially 20-30), the constructor will be huge and injecting all these repositories seems cumbersome.
Is there a better pattern/approach to consuming all the datasources rather than using different repositories?
Would a facade or some other pattern be more appropriate?
Very generic examples:
public class MyObject(){
public IEnumerable<Cat> Cats { get; set; }
public IEnumerable<Dog> Dogs { get; set; }
public IEnumerable<Fish> Fish { get; set; }
}
public class BusinessLogic{
private readonly ISourceARepository _sourceA;
private readonly ISourceBRepository _sourceB;
private readonly ISourceCRepository _sourceC;
public BusinessLogic(ISourceARepository sourceA, ISourceBRepository sourceB, ISourceCRepository sourceC){
_sourceA = sourceA;
_sourceB = sourceB;
_sourceC = sourceC;
}
private Dog MapSourceARecordToDog(SourceARecord record){
var result = new Dog();
if(record != null){
result.Name = record.NameField;
result.Age = record.Age;
}
return result;
}
private Cat MapSourceBRecordToCat(SourceBRecord record){
var result = new Cat();
if(record != null){
result.Name = record.NameField;
result.Weight = record.WeightField;
}
return result;
}
private Fish MapSourceCRecordToFish(SourceCRecord record){
var result = new Fish();
if(record != null){
result.ID = record.IDField;
result.Name = record.NameField;
}
return result;
}
public MyObject GetResults(){
var result = new MyObject();
result.Dogs = _sourceA.GetAll().Select(MapSourceARecordToDog).ToList();
result.Cats = _sourceB.GetAll().Select(MapSourceBRecordToCat).ToList();
result.Fish = _sourceC.GetAll().Select(MapSourceCRecordToFish).ToList();
return result;
}
}
public class SourceARespository : ISourceARepository{
public IEnumerable<SourceAResult> GetAll(){
return new List<SourceAResult>();
}
}
public class SourceBRespository : ISourceBRepository{
public IEnumerable<SourceBResult> GetAll(){
return new List<SourceBResult>();
}
}
public class SourceCRespository : ISourceCRepository{
public IEnumerable<SourceCResult> GetAll(){
return new List<SourceCResult>();
}
}
Update:
This is not a duplicate of the constructor madness question, because in this scenario, a class needs many different datasources, but still has single responsibility. Hence, it warrants its own explanation and answer.
You should only be injecting one repository per entity into a consumer that depends on it. You may also choose to adapt the repository with a business class intermediary.
UPDATE:
Based on the information provided in the question and the problem statement, here is one possible solution. Define your core infrastructure like this:
public abstract class Entity<TEntity, TDomainObject, TIRepository>
where TEntity : Entity<TEntity, TDomainObject, TIRepository>
where TDomainObject : Entity<TEntity, TDomainObject, TIRepository>.BaseDomainObject, new()
where TIRepository : Entity<TEntity, TDomainObject, TIRepository>.IBaseRepository
{
public class BaseDomainObject {}
public interface IBaseRepository
{
IEnumerable<TDomainObject> GetAll();
IEnumerable<T> GetAllMapped<T>(Func<TDomainObject, T> mapper);
}
public class BaseRepository : IBaseRepository
{
public IEnumerable<TDomainObject> GetAll()
{
return new List<TDomainObject>();
}
public IEnumerable<T> GetAllMapped<T>(Func<TDomainObject, T> mapper)
{
return this.GetAll().Select(mapper);
}
}
}
Define your source entities like this:
public class SourceA : Entity<SourceA, SourceA.DomainObject, SourceA.IRepository>
{
public class DomainObject : BaseDomainObject
{
public string Name;
public int Age;
}
public interface IRepository : IBaseRepository {}
public class Repository : BaseRepository, IRepository {}
}
public class SourceB : Entity<SourceB, SourceB.DomainObject, SourceB.IRepository>
{
public class DomainObject : BaseDomainObject
{
public string Name;
public decimal Weight;
}
public interface IRepository : IBaseRepository {}
public class Repository : BaseRepository, IRepository {}
}
public class SourceC : Entity<SourceC, SourceC.DomainObject, SourceC.IRepository>
{
public class DomainObject : BaseDomainObject
{
public Guid Id;
public string Name;
}
public interface IRepository : IBaseRepository {}
public class Repository : BaseRepository, IRepository {}
}
Then define an ISourceRepositoryContext interface like this and add each source repository interface here:
public interface ISourceRepositoryContext
{
SourceA.IRepository SourceARepository { get; }
SourceB.IRepository SourceBRepository { get; }
SourceC.IRepository SourceCRepository { get; }
}
Then define a default implementation for the interface:
public class DefaultSourceRepositoryContext : ISourceRepositoryContext
{
public SourceA.IRepository SourceARepository => new SourceA.Repository();
public SourceB.IRepository SourceBRepository => new SourceB.Repository();
public SourceC.IRepository SourceCRepository => new SourceC.Repository();
}
Define your result transport objects:
public class Dog
{
public string Name;
public int Age;
}
public class Cat
{
public string Name;
public decimal Weight;
}
public class Fish
{
public Guid Id;
public string Name;
}
public class MyObject
{
public IEnumerable<Cat> Cats { get; set; }
public IEnumerable<Dog> Dogs { get; set; }
public IEnumerable<Fish> Fish { get; set; }
}
Then consume the ISourceRepositoryContext in your BusinessLogic class:
public class BusinessLogic
{
protected ISourceRepositoryContext repositories;
public BusinessLogic(ISourceRepositoryContext repositories)
{
this.repositories = repositories;
}
public MyObject GetResults(string param1)
{
return new MyObject()
{
Dogs = this.repositories.SourceARepository.GetAllMapped
(domainObject=>new Dog
{
Age = domainObject.Age,
Name = domainObject.Name
}),
Cats = this.repositories.SourceBRepository.GetAllMapped
(domainObject=>new Cat
{
Name = domainObject.Name,
Weight = domainObject.Weight
}),
Fish = this.repositories.SourceCRepository.GetAllMapped
(domainObject=>new Fish
{
Id = domainObject.Id,
Name = domainObject.Name
}),
};
}
}
I've confirmed that the above compiles under C# 6.0.
I would recommend changing IRepository to IBusiness in Entity and split out the data access concerns from into an IDataAccess interface that only the IBusiness implementors receive via their constructors. And then change the ISourceRepositoryContext to ISourceEntities and change the IRepository properties in that interface to IBusiness properties instead.
The BusinessLogic class is the part that really concerns me. Are you sure this one class won't be taking on too many concerns? Is this supposed to be a UoW class?
For a more complete solution based on similar techniques, check out my answer to this other question: .NET Managing Layers Relationships

How do I simplify this nested generic typed class

public interface IHasFeature<TFeature> {
TFeature Feature { get; set; }
}
public class FeatureOne {
/*...*/
}
public class ProductOne : IHasFeature<FeatureOne> {
public FeatureOne Feature { get; set; }
}
public abstract class BaseContainer<TProduct, TFeature>
where TProduct : IHasFeature<TFeature> {
public TProduct Product { get; set; }
public void DoProcess() {
var result = Product.Feature.Execute(); //Execute is an extension method
}
}
public class MyContainer : BaseContainer<ProductOne, FeatureOne> {
/*...*/
}
Works when I do:
MyContainer : BaseContainer<ProductOne, FeatureOne>
But I want to:
MyContainer : BaseContainer<ProductOne>
ProductOne : IHasFeature<...> should already contain the nested generic feature TFeature, I don't want to repeat them again in MyContainer construction.
Any idea how I can improve this? Thanks.
EDIT2 -----------------------
Removed new keyword, it was wrong as Nenad said.
The compile translates your call to the extension method Execute() as a call to the static method of the class where it is defined. So, when you call Product.Feature.Execute() inside DoProcess(), the compiler needs to know the type of Product.Feature in order to call the appropriate extension method.
What I suggest is write IHasFeature like this
public interface IHasFeature
{
void DoSomethingWithFeature();
}
If you want to keep IHasFeature generic, the best you can do is define BaseContainer without specifying TFeature and implement DoProcess() in MyContainer.
public abstract class BaseContainer<TProduct>
{
public TProduct Product { get; set; }
public abstract void DoProcess();
}
public class MyContainer : BaseContainer<ProductOne>
{
public override void DoProcess()
{
Product.Feature.Execute();
}
}

Categories