using IdType=System.Int32;
using IdentityType=System.String;
using static System.Console;
public static void Main()
IDomainObjectSaver<Age> s=new Saver<Age>();
IDomainObjectSaver<IDomainObject> ss=new Saver<IDomainObject>();
PersonSaver personSaver=new PersonSaver();
EmployeeSaver employeeSaver=new EmployeeSaver();
public interface IUniqueId<TId>
public void SetId(TId id);
public interface ITraceable<TIdentity>
{ public TIdentity Identity { get;set; } }
public interface IDomainObject<TId, TIdentity> : IUniqueId<TId>, ITraceable<TIdentity>
public bool IsNew { get; }
public bool IsDirty { get; }
public bool IsDeleted { get; }
public interface IDomainObject<in TState> : IDomainObject<IdType, IdentityType>
where TState : IDomainObject<IdType, IdentityType>;
public interface IDomainObject : IDomainObject<IdType, IdentityType>;
public interface IDomainObjectSaver<in TState>
where TState : IDomainObject
{ public void Save(TState domainObject); }
public interface IDomainObjectSaver : IDomainObjectSaver<IDomainObject>;
public interface IDomainObjectPersister<in TState>
where TState : IDomainObject
public IdType Add(TState domainObject);
public void Update(TState domainObject);
public void Delete(TState domainObject);
public interface IDomainObjectPersister : IDomainObjectPersister<IDomainObject>;
public abstract class DomainObject : IDomainObject
protected bool _isNew, _isDirty, _isDeleted;
public bool IsNew =>_isNew;
public bool IsDirty =>_isDirty;
public bool IsDeleted =>_isDeleted;
public IdentityType Identity { get;set; }
public void SetId(IdType id) => (_id, _isNew) = (id, false);
public override string ToString() => this.GetType().ToString();
public class Person : DomainObject, IDomainObject<Person>
public string First { get;set; }
public string Last { get;set; }
public class Employee : Person, IDomainObject<Employee>
public string Title { get;set; }
public new string ToString() => this.GetType().ToString();
public struct Age : IDomainObject
private bool _isNew, _isDirty, _isDeleted;
public bool IsNew =>_isNew;
public bool IsDirty =>_isDirty;
public bool IsDeleted =>_isDeleted;
public IdentityType Identity { get;set; }
public void SetId(IdType id) => (_id, _isNew) = (id, false);
public string Value=>"Old";
public struct ExportedDomainObjectType
public ExportedDomainObjectType(string domainObjectName, string domainObjectFullName, string persisterName, Type persisterType, bool isStruct)
=> ( DomainObjectName, DomainObjectFullName, PersisterName, PersisterType, IsStruct ) = ( domainObjectName, domainObjectFullName, persisterName, persisterType, isStruct );
public string DomainObjectName { get;init; }
public string DomainObjectFullName{ get;init; }
public string PersisterName { get;init; }
public Type PersisterType { get;set; }
public bool IsStruct { get;init; }
public override string ToString()=>$"DomainObjectName: {DomainObjectName}, DomainObjectFullName: {DomainObjectFullName}, PersisterName: {PersisterName}, PersisterType: {PersisterType.ToString()}, IsStruct: {IsStruct}";
public class DomainObjectSaver<TState> : IDomainObjectSaver<TState>
where TState : IDomainObject
public void Save(TState domainObject)=>WriteLine($"DomainObjectSaver<TState>.Save");
public class Saver<TState> : DomainObjectSaver<TState>
where TState : IDomainObject
private const string BaseOfAllDomainObjects="IDomainObject";
private const string PersisterPostfix="Persister";
private const string PersisterInterfaceName=BaseOfAllDomainObjects + PersisterPostfix;
protected static ExportedDomainObjectType [] ExportedDomainObjectTypes=null;
var assembly=System.Reflection.Assembly.GetExecutingAssembly();
ExportedDomainObjectTypes =
(from t in assembly.GetExportedTypes()
let DomainObjectName=t.Name
let DomainObjectFullName=t.FullName
let PersisterName=t.FullName + PersisterPostfix
let PersisterType=assembly.GetType(PersisterName, false, true) ?? assembly.GetType(PersisterName + "<>", false, true) ?? typeof(object)
where ( t.IsClass || t.IsValueType )
&& t.GetInterface(BaseOfAllDomainObjects) is not null
select new ExportedDomainObjectType( DomainObjectName, DomainObjectFullName, PersisterName, PersisterType, IsStruct )).ToArray();
bool isPersisterMissing=false;
bool isInterfaceMissing=false;
string errorMessage=$"\nPersister(s) Error!\n\tDomain Objects MUST have their own persister, and they must implement {PersisterInterfaceName} interface. You are missing...\n";
for(var c=0;c<ExportedDomainObjectTypes.Length;c++)
var persisterType=ExportedDomainObjectTypes[c].PersisterType;
var persisterInterfaces=persisterType.GetInterfaces();
var hasPersisterInterface=persisterInterfaces.Any(
i=>(i.IsGenericType && i.GetGenericTypeDefinition()==typeof(IDomainObjectPersister<>) ) || !i.IsGenericType );
foreach(var i in persisterInterfaces)
var persisterInterface=persisterType.GetInterface(PersisterInterfaceName) ?? persisterType.GetInterface(PersisterInterfaceName + "<>");
if(persisterType is null || persisterType.Equals(typeof(object)))
errorMessage+=$"\t\tMissing Type\t\t->\t{ExportedDomainObjectTypes[c].PersisterName}\n";
else if(!hasPersisterInterface)
errorMessage+=$"\t\tMissing Interface\t->\t{ExportedDomainObjectTypes[c].PersisterName} : {PersisterInterfaceName}\n";
if(persisterType is not null && persisterInterface is not null)
ExportedDomainObjectTypes[c].PersisterType=persisterType;
if(isPersisterMissing || isInterfaceMissing) throw new System.ApplicationException(errorMessage);
WriteLine("Static ctor:" + e.Message);
protected void save(IDomainObject domainObject)
WriteLine(domainObject.GetType());
if(domainObject is Employee)
IDomainObjectPersister<Employee> ep=new EmployeePersister();
ep.Add(domainObject as Employee);
WriteLine($"Saver<TState>.save IDomainObject {domainObject.ToString()}");
public void Save(TState domainObject)
WriteLine($"Saver<TState>.Save {domainObject.ToString()}");
public class PersonSaver : Saver<Person>
public void Save(Person person) => WriteLine($"PersonSaver.Save {person.ToString()}");
public class EmployeeSaver : Saver<Employee>
public void Save(Employee e)=>WriteLine($"Employee.Save {e.ToString()}");
public class AgeSaver : Saver<Age>
public void Save(Employee e)=>WriteLine($"AgeSaver.Save {e.ToString()}");
public abstract class DomainObjectPersister<TState> : IDomainObjectPersister<TState>
where TState : IDomainObject
public IdType Add(TState domainObject)
WriteLine("DomainObjectPersister<TState>.Add" + this.GetType().ToString());
public void Update(TState domainObject)
WriteLine("DomainObjectPersister<TState>.Update" + this.GetType().ToString());
public void Delete(TState domainObject)
WriteLine("DomainObjectPersister<TState>.Delete" + this.GetType().ToString());
public partial class PersonPersister : IDomainObjectPersister<Person>
public IdType Add(Person domainObject)
WriteLine(this.GetType().ToString());
public void Update(Person domainObject)
WriteLine(this.GetType().ToString());
public void Delete(Person domainObject)
WriteLine(this.GetType().ToString());
public partial class EmployeePersister : IDomainObjectPersister<Employee>
public IdType Add(Employee domainObject)
WriteLine($"EmployeePersister.Add {this.GetType().ToString()}");
public void Update(Employee domainObject)
WriteLine(this.GetType().ToString());
public void Delete(Employee domainObject)
WriteLine(this.GetType().ToString());
public partial class AgePersister : IDomainObjectPersister<Age>
public IdType Add(Age domainObject)
WriteLine(this.GetType().ToString());
public void Update(Age domainObject)
WriteLine(this.GetType().ToString());
public void Delete(Age domainObject)
WriteLine(this.GetType().ToString());
public partial class Persister<TDomainObject>
public void Write2(TDomainObject domainObject)=>WriteLine($"Persister<TDomainObject> {domainObject.ToString()}\n");