using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Frozen;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq.Expressions;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
using System.Threading.Channels;
using System.Threading.Tasks;
using static System.Console;
using static System.Environment;
using static System.Threading.Tasks.TaskExtensions;
using STT=System.Threading.Tasks;
using CMN=System.Runtime.CompilerServices.CallerMemberNameAttribute;
using CFP=System.Runtime.CompilerServices.CallerFilePathAttribute;
using CLN=System.Runtime.CompilerServices.CallerLineNumberAttribute;
using DN=System.Diagnostics.CodeAnalysis.DisallowNullAttribute;
using NN=System.Diagnostics.CodeAnalysis.NotNullAttribute;
using NNW=System.Diagnostics.CodeAnalysis.NotNullWhenAttribute;
using DPV=System.Runtime.InteropServices.DefaultParameterValueAttribute;
using dt=System.DateTime;
using Core.Common.Helpers;
using Core.ErrorHandling.Exceptions;
using static ExtensionMethods.EnumerableMethods;
using static DebugMethods;
using static UtilityMethods;
using IdType=System.Int32;
using TIdentity=System.String;
using DI=Core.Dependencies.DependencyInversion;
using TPermissions=System.Collections.Generic.Dictionary<string, System.Collections.Generic.List<string>>;
public static Data<Person> People=new();
public static Data<Employee> Employees=new();
public class Data<T> : List<T>;
dynamic ex=new ExpandoObject();
Console.WriteLine(ex.First);
var dic=(IDictionary<string, object>)ex;
Console.WriteLine(dic["First"]);
DI.Global.AddService<IIngressConsumerService<Person>>( ()=>new IngressService<Person>(new BusinessService<Person>( new SqlProvider<Person>( new SqlPersonProvider() ) )) );
DI.TypeNameResolver=type=>type.Name.Substring(1);
DI.Global.AddService("Core.Services.IIngressConsumerService`1[Core.Domain.Employee]", "Core.Services.IngressService`1[Core.Domain.Employee]");
DI.Global.AddService<IIngressProducerService<Person, PersonId>, IngressService<Person, PersonId>>();
DI.Global.AddService<IIngressProducerService<Employee, EmployeeId>, IngressService<Employee, EmployeeId>>();
DI.Global.AddService<IBusinessService<Person>>();
DI.Global.AddService<IBusinessService<Employee>>();
DI.Global.AddService<IServiceProvider<Person>, SqlProvider<Person>>();
DI.Global.AddService<IServiceProvider<Employee>, RdbmsProvider<Employee>>();
DI.Global.AddService<ICrudProvider<Person>, SqlPersonProvider>();
DI.Global.AddService<ICrudProvider<Employee>, SqlEmployeeProvider>();
DI.Global.AddService<IServiceProvider<Age>, EmailProvider<Age>>();
public static Data Data=new();
public static void Main()
var ep=DI.Global.GetService<IServiceProvider<Age>>();
var pConsumer=DI.Global.GetService<IIngressConsumerService<Person>>();
var eConsumer=DI.Global.GetService<IIngressConsumerService<Employee>>();
var eProducer=DI.Global.GetService<IIngressProducerService<Employee,EmployeeId>>();
WL(((IStateManaged)p).State.ToString());
var er=eProducer.Get(e=>e.First=="f");
Hi(((IStateManaged)e).State.IsNew);
er=eProducer.Get(e=>e.First=="tug");
er=eProducer.Get(e=>e.Last=="McG");
WL(this.GetType()?.Name ?? " isnull");
WL(this.GetType().DeclaringType?.Name ?? " isnull");
namespace Core.Interfaces
public interface INew <T> { public T Create(); }
public interface IConsumer : IConsumer<IDomainObject>;
public interface IConsumer <T>
public void Process(T input) ;
public virtual void ProcessParallel(T input){}
public virtual void ProcessAsync(T input){}
public virtual void Save(T input)=>Process(input);
public interface ISaver <T> { public void Save(T input); }
public interface IWriter <T> { public void Write(T input); }
public interface IProducer : IProducer<IDomainObject, IEntityId>;
public interface IProducer <T> : IProducer<T, IEntityId>;
public interface IProducer <T, in TEntityId>
public T Get(TEntityId id) ;
public IEnumerable<T> Get(Expression<Predicate<T>> predicate);
public interface IReader <T, in TEntityId>
where TEntityId : IEntityId
public T Read(TEntityId id) => throw new NotImplementedException("Refer to the interface definition.");
public IEnumerable<T> Read(Expression<Predicate<T>> predicate) => throw new NotImplementedException("Refer to the interface definition.");
public interface IConsumerProducer <T> { public T Process(T input); }
public interface IConsumerProducer <Tin, Tout> { public Tout Process(Tin input); }
public interface IEntityId : IEntityId<IdType>
public static IdType NewId
Core.IdManager.GetId(ref id);
public interface IEntityId<T>
public static IEntityId<T> Empty => new EntityId<T>(default);
public interface IEntityObjectId : IEntityObjectId<EntityId<IdType>>;
public interface IEntityObjectId<TEntityId>
where TEntityId : IEntityId<IdType>
public TEntityId EntityId {get;}
public void SetId(TEntityId id);
public static TEntityId Empty => (TEntityId)System.Activator.CreateInstance(typeof(TEntityId), [default]);
public interface ISecurable <TIdentity>
public TIdentity Identity { get;set; }
public interface ISecurable : ISecurable<TIdentity>;
public interface IStateful
public bool IsDirty {get;}
public bool IsDeleted {get;}
public virtual bool IsActionable => IsNew || IsDirty || IsDeleted;
public interface IObjectStateManaged : ISecurable
public event DomainObjectEventHandler ItemRemoved;
public ObjectStateManager State { get; }
public interface IStateManaged : IObjectStateManaged;
public interface IActionable<T>
public virtual bool IsActionable =>true;
public virtual bool IsValidToInsert =>false;
public interface IEmptyObject<T>
{ public static T Empty=default(T); }
public interface IEmptyAggregateObject<T>
{ public static IEnumerable<T> Empty=Enumerable.Empty<T>(); }
public interface IDomainObject : IDomainObject<IDomainObject>;
public interface IDomainObject<T> : IStateManaged, IActionable<T>, IEmptyObject<T>;
public interface IBusinessObject : IBusinessObject<IBusinessObject>;
public interface IBusinessObject<T> : IStateManaged, IActionable<T>, IEmptyObject<T>;
public interface IServiceObject : IServiceObject<IServiceObject>;
public interface IServiceObject<T> : IStateManaged, IActionable<T>, IEmptyObject<T>;
public interface IDataObject : IDataObject<IDataObject>;
public interface IDataObject<T> : IStateManaged, IActionable<T>, IEmptyObject<T>
public CrudOperation Operation { get; }
public interface IDomainAggregate <T> : IStateful, IEnumerable<T>, IEnumerable, IEmptyAggregateObject<T>
public IList<T> Items {get;}
public new virtual bool IsNew=>this.Any(i=>i.State.IsNew);
public new virtual bool IsDirty=>this.Any(i=>i.State.IsDirty);
public new virtual bool IsDeleted=>this.Any(i=>i.State.IsDeleted);
public new virtual bool IsActionable => IsNew || IsDirty || IsDeleted;
public virtual void OnItemRemoved(object sender)
if(item.State.IsNew) Items.Remove( item );
WL($"IDomainAggregate.OnItemRemoved: {item.ToString()}");
public interface ICreate <T> { public T Add(T input); }
public interface ICreate <Tin, Tout> { public Tout Add(Tin input); }
public interface IUpdate <T> { public void Update(T input); }
public interface IDelete <T> { public void Delete(T input); }
public interface IRead <T>
public T Read(IdType id);
public IDomainAggregate<T> Read(Expression<Predicate<T>> predicate);
public interface IReadAggregate<T,out TAggregate>
where TAggregate : IDomainAggregate<T>
public TAggregate Read(Expression<Predicate<T>> predicate);
public interface ICrudProvider<Tin, Tout> : ICreate<Tin, Tout>, IUpdate<Tin>, IDelete<Tin>, IRead<Tout>
where Tin : IStateManaged
where Tout : IStateManaged;
public interface ICrudProvider<T> : ICreate<T>, IUpdate<T>, IDelete<T>, IRead<T>
public interface ISecurityToken : ISecurable
public DateTime SessionStart { get; }
public DateTime SessionEnd { get; }
public virtual TimeSpan SessionDuration { get=>dt.UtcNow-SessionStart; }
public virtual bool IsExpired { get=>dt.UtcNow>SessionEnd; }
public interface ISecureService
public ISecurityToken Token {get;}
public void Authenticate(TIdentity identity);
public bool Authorize(TIdentity identity);
public interface IServiceProxy
public ISecurityToken Token {get;}
public void Request<TService>(TService ServiceType) where TService : ISecureService;
namespace Core.Controllers.Security
public record SecurityToken<TIdentity>(TIdentity Id, IList<string> Errors=null);
public class SecurityIngress(SecurityToken<TIdentity> token)
public bool TryAuthenticate(TIdentity Id, out SecurityToken<TIdentity> token)
public bool TryAuthorize<TAcessLevel>(SecurityToken<TIdentity> token)=>true;
public interface IIngressConsumerService : IConsumer;
public interface IIngressConsumerService<T> : IConsumer<T>;
public interface IIngressProducerService : IProducer;
public interface IIngressProducerService<T> : IProducer<T>;
public interface IIngressProducerService<T, in TEntityId> : IProducer<T, TEntityId>;
public interface IIngressConsumerProducerService<Tin, Tout> : IConsumerProducer<Tin, Tout>;
public abstract class IngressServiceBase<T>(IBusinessService<T> businessService)
where T : IDomainObject<T>
private protected IBusinessService<T> _businessService=businessService;
public abstract class IngressConsumerProducerServiceBase<Tin,Tout>(IBusinessService<Tin,Tout> businessService)
where Tin : IDomainObject<Tin>
private protected IBusinessService<Tin,Tout> _businessService=businessService;
public class IngressService<T>(IBusinessService<T> businessService) : IngressServiceBase<T>(businessService), IIngressConsumerService<T>
where T : IDomainObject<T>
public virtual void Process(T input)
WL($"{this.GetType().Name}.Process({input.GetType().Name})");
if(((IDomainObject<T>)input).IsActionable) _businessService.Process(input); else WL("Not Actionable");
public class IngressService<T, TEntityId>(IBusinessService<T> businessService) : IngressServiceBase<T>(businessService), IIngressProducerService<T, TEntityId>
where T : IDomainObject<T>
where TEntityId : IEntityId
public virtual T Get(TEntityId id)
WL($"{this.GetType().Name}.Get({id.GetType().Name})");
return _businessService.Get(id) ?? IDomainObject<T>.Empty;
public virtual IEnumerable<T> Get(Expression<Predicate<T>> predicate)
WL($"{this.GetType().Name}.Get({predicate.GetType().Name})");
return _businessService.Get(predicate) ?? IDomainAggregate<T>.Empty;
public class IngressConsumerProducerService<Tin, Tout, TEntityId>(IBusinessService<Tin, Tout> businessService) : IngressConsumerProducerServiceBase<Tin, Tout>(businessService), IIngressConsumerProducerService<Tin, Tout>
where Tin : IDomainObject<Tin>
where TEntityId : IEntityId
public Tout Process(Tin input)
WL($"{this.GetType().Name}.Process({input.GetType().Name})");
public interface IBusinessService : IProducer, IConsumer;
public interface IBusinessService<T> : IProducer<T>, IConsumer<T>;
public interface IBusinessService<Tin, Tout> : IProducer<Tout>, IConsumer<Tin>;
public abstract class BusinessServiceBase<T>(IServiceProvider<T> serviceProvider)
where T : IBusinessObject<T>
private protected IServiceProvider<T> _serviceProvider=serviceProvider;
public class BusinessService<T>(IServiceProvider<T> serviceProvider) : BusinessServiceBase<T>(serviceProvider), IBusinessService<T>
where T : IBusinessObject<T>
public virtual void Process(T input)
WL($"{this.GetType().Name}.Process({input.GetType().Name})");
Hi(_serviceProvider is null);
_serviceProvider.Process(input);
public virtual T Get(IEntityId id)
WL($"{this.GetType().Name}.Get({id.GetType().Name})");
return _serviceProvider.Get(id) ?? IBusinessObject<T>.Empty;
public virtual IEnumerable<T> Get(Expression<Predicate<T>> predicate)
WL($"{this.GetType().Name}.Get({predicate.GetType().Name})");
return _serviceProvider.Get(predicate) ?? IDomainAggregate<T>.Empty;
public interface IServiceProvider : IProducer, IConsumer;
public interface IServiceProvider<T> : IProducer<T>, IConsumer<T>;
public interface IServiceProvider<Tin, Tout> : IProducer<Tout>, IConsumer<Tin>;
public abstract partial class ServiceProvider<T>(IServiceProvider<T> serviceProvider) : IServiceProvider<T>
where T : IServiceObject<T>
private protected IServiceProvider<T> _serviceProvider=serviceProvider;
public virtual void Process(T input)
WL($"ServiceProvider.{this.GetType().Name}.Process({input.GetType().Name})");
_serviceProvider.Process(input);
public T Get(IEntityId id)
WL($"ServiceProvider.{this.GetType().Name}.Get({id.GetType().Name})");
var result=_serviceProvider.Get(id);
return result ?? IServiceObject<T>.Empty;
public IEnumerable<T> Get(Expression<Predicate<T>> predicate)
WL($"ServiceProvider.{this.GetType().Name}.Get({predicate.GetType().Name})");
var result=_serviceProvider.Get(predicate);
result.For(r=>PostProcess(ref r));
return result ?? IDomainAggregate<T>.Empty;
partial void PreProcess(ref T input);
partial void PostProcess(ref T output);
public abstract partial class DataServiceProvider<T>(ICrudProvider<T> serviceProvider) : IServiceProvider<T>
private protected ICrudProvider<T> _serviceProvider=serviceProvider;
public virtual void Process(T input)
WL($"DataServiceProvider.{this.GetType().Name}.Process({input.GetType().Name})");
if(!((IStateful)input.State).IsActionable) return;
if(!((IActionable<T>)input).IsActionable) return;
switch(((IDataObject<T>)input).Operation)
case CrudOperation.Insert : Add(input); break;
case CrudOperation.Delete : Delete(input);break;
case CrudOperation.Update : Update(input);break;
WriteLine("No state, so do nothing to...\n\t" + input.ToString());break;
public virtual void Process(Expression<Action<T>> action, T input)
WL($"DataServiceProvider.{this.GetType().Name}.Process({input.GetType().Name})");
public T Get(IEntityId id)
WL($"DataServiceProvider.{this.GetType().Name}.Get({id.GetType().Name})");
return Read(id) ?? IDataObject<T>.Empty;
public IEnumerable<T> Get(Expression<Predicate<T>> predicate)
WL($"DataServiceProvider.{this.GetType().Name}.Get({predicate.GetType().Name})");
return Read(predicate) ?? IDomainAggregate<T>.Empty;
partial void PreProcess(ref T input);
partial void PostProcess(ref T output);
protected abstract T Add(T input);
protected abstract void Update(T input);
protected abstract void Delete(T input);
protected abstract T Read(IEntityId id);
protected abstract IEnumerable<T> Read(Expression<Predicate<T>> predicate);
public class RdbmsProvider<T>(ICrudProvider<T> serviceProvider) : DataServiceProvider<T>(serviceProvider)
protected override T Add(T obj)
WL($"{this.GetType().Name}.Add({obj.GetType().Name})");
WL("Valid to insert: " + ((IActionable<T>)obj).IsValidToInsert);
if(!((IActionable<T>)obj).IsValidToInsert)
return _serviceProvider.Add(obj);
protected override void Update(T obj)
WL($"{this.GetType().Name}.Update({obj.GetType().Name})");
_serviceProvider.Update(obj);
protected override void Delete(T obj)
WL($"{this.GetType().Name}.Delete({obj.GetType().Name})");
_serviceProvider.Delete(obj);
protected override T Read(IEntityId id)
WL($"{this.GetType().Name}.Read({id.GetType().Name})");
return _serviceProvider.Read(id.Id) ?? IDataObject<T>.Empty;
protected override IEnumerable<T> Read(Expression<Predicate<T>> predicate)
WL($"{this.GetType().Name}.Read({predicate.GetType().Name})");
return _serviceProvider.Read(predicate) ?? IDomainAggregate<T>.Empty;
public class SqlProvider<T>(ICrudProvider<T> serviceProvider) : DataServiceProvider<T>(serviceProvider)
protected override T Add(T obj)
WL($"{this.GetType().Name}.Add({obj.GetType().Name})");
WL("Valid to insert: " + ((IActionable<T>)obj).IsValidToInsert);
if(!((IActionable<T>)obj).IsValidToInsert)
WL("INVALID TO INSERT\n");
return _serviceProvider.Add(obj);
protected override void Update(T obj)
WL($"{this.GetType().Name}.Update({obj.GetType().Name})");
_serviceProvider.Update(obj);
protected override void Delete(T obj)
WL($"{this.GetType().Name}.Delete({obj.GetType().Name})");
_serviceProvider.Delete(obj);
protected override T Read(IEntityId id)
WL($"{this.GetType().Name}.Read({id.GetType().Name})");
return _serviceProvider.Read(id.Id) ?? IDataObject<T>.Empty;
protected override IEnumerable<T> Read(Expression<Predicate<T>> predicate)
WL($"{this.GetType().Name}.Read({predicate.GetType().Name})");
return _serviceProvider.Read(predicate) ?? IDomainAggregate<T>.Empty;
public class EmailProvider<T>() : ServiceProvider<T>(null)
where T : IServiceObject<T>
public void Test(string s, string x)
private void Test<TT,S>(DateTime d, TT t, S tt, double p)
public void Test(DateTime d, string t, int tt, double p)
public class SqlPersonProvider : ICrudProvider<Person>
public Person Add(Person obj)
WL($"{this.GetType().Name}.Add({obj.GetType().Name})");
((IEntityObjectId<PersonId>)obj).SetId(new PersonId(IEntityId.NewId));
public void Update(Person obj)
WL($"{this.GetType().Name}.Update({obj.GetType().Name})");
Data.People.RemoveAll(p=>p.Id==obj.Id);
public void Delete(Person obj)
WL($"{this.GetType().Name}.Delete({obj.GetType().Name})");
public Person Read(IdType id)
WL($"{this.GetType().Name}.Read({id.GetType().Name})");
return null ?? IDataObject<Person>.Empty;
public IDomainAggregate<Person> Read(Expression<Predicate<Person>> predicate)
WL($"{this.GetType().Name}.Read({predicate.GetType().Name})");
return new People(Data.People.Where(p=>predicate.Compile()(p)) ?? IDomainAggregate<Person>.Empty);
public class SqlEmployeeProvider : ICrudProvider<Employee>
public Employee Add(Employee obj)
WL($"{this.GetType().Name}.Add({obj.GetType().Name})");
((IEntityObjectId<EmployeeId>)obj).SetId(new EmployeeId(IEntityId.NewId));
public void Update(Employee obj)
WL($"{this.GetType().Name}.Update({obj.GetType().Name})");
Data.Employees.RemoveAll(e=>e.Id==obj.Id);
public void Delete(Employee obj)
WL($"{this.GetType().Name}.Delete({obj.GetType().Name})");
Data.Employees.Remove(obj);
public Employee Read(IdType id)
WL($"{this.GetType().Name}.Read({id.GetType().Name})");
return Data.Employees.Single(i=>i.Id==id) ?? IDataObject<Employee>.Empty;
public IDomainAggregate<Employee> Read(Expression<Predicate<Employee>> predicate)
WL($"{this.GetType().Name}.Read({predicate.GetType().Name})");Hi();
var r= new Employees(Data.Employees.Where(e=>predicate.Compile()(e)) ?? IDomainAggregate<Employee>.Empty);
public delegate void DomainObjectEventHandler(object sender);
public delegate void DomainObjectEventHandler<T>(T sender) where T : IStateManaged;
public readonly record struct EntityId(IdType Id) : IEntityId
public static IEntityId<IdType> Empty => new EntityId<IdType>(default);
public static implicit operator IdType(EntityId uniqueId)=>uniqueId.Id;
public readonly record struct EntityId<T>(T Id) : IEntityId<T>
public static IEntityId<T> Empty => new EntityId<T>(default);
public static implicit operator T(EntityId<T> uniqueId)=>uniqueId.Id;
public readonly record struct PersonId(IdType Id) : IEntityId
public static PersonId Empty => new(default);
public static implicit operator IdType(PersonId uniqueId)=>uniqueId.Id;
public readonly record struct EmployeeId(IdType Id) : IEntityId
public static EmployeeId Empty => new(default);
public static implicit operator IdType(EmployeeId uniqueId)=>uniqueId.Id;
public readonly record struct AgeId(IdType Id) : IEntityId
public static AgeId Empty => new(default);
public static implicit operator IdType(AgeId uniqueId)=>uniqueId.Id;
public struct Value<T>(Action setDirtyAction)
private Action _setDirtyAction=setDirtyAction;
public Value(T value, Action setDirtyAction) : this(setDirtyAction) { Hi(); _value=value;}
public void Set(T value, [CMN]string caller="")
if(isReallyChanged(value)) { _value=value; _setDirtyAction?.Invoke(); }
private bool isReallyChanged(T value) =>(_value is null && value is not null) || (_value is not null && value is null) || (_value is not null && !_value.Equals(value));
public static implicit operator T (Value<T> value)=>value._value;
public class ObjectState : IStateful
protected bool _isNew=true, _isDirty, _isDeleted;
internal ObjectState(bool isNew, bool isDirty, bool isDeleted)
=> ( _isNew, _isDirty, _isDeleted ) = ( isNew, isDirty, isDeleted );
public virtual bool IsNew =>_isNew;
public virtual bool IsDirty =>_isDirty;
public virtual bool IsDeleted =>_isDeleted;
protected internal virtual bool IsActionable => ((IStateful)this).IsActionable;
public static implicit operator CrudOperation(ObjectState state) => state switch
{IsNew:true} => CrudOperation.Insert,
{IsDirty:true} => CrudOperation.Update,
{IsDeleted:true} => CrudOperation.Delete,
public class ObjectStateManager : ObjectState
public event DomainObjectEventHandler? ItemRemoved;
public event DomainObjectEventHandler? ItemChanged;
public ObjectStateManager(){}
public ObjectStateManager(DomainObjectEventHandler onItemRemoved) => ItemRemoved+=onItemRemoved;
( _isNew, _isDirty, _isDeleted ) = (false, false, true);
WL($"DomainObjectState.SetDeleted: {this.ToString()}");
ItemRemoved?.Invoke(this);
public void SetDirty()=> SetDirty(true);
public void SetDirty(bool isDirty)
_isDirty = _isDeleted || _isNew ? false : isDirty;
ItemChanged?.Invoke(this);
public void SetNew(bool isNew=true) => ( _isNew, _isDirty, _isDeleted ) = (isNew, false, false);
public void Reset()=>_isNew=_isDirty=_isDeleted=false;
public new string ToString()=>$"IsNew: {IsNew}, IsDirty: {IsDirty}, IsDeleted: {IsDeleted} ";
public class DomainObject : IDomainObject, IBusinessObject, IServiceObject, IDataObject<IDomainObject>, IObjectStateManaged, IEntityId
private ObjectStateManager _state=new();
public event DomainObjectEventHandler ItemRemoved;
public event DomainObjectEventHandler ItemChanged;
_state.ItemRemoved+=OnItemRemoved;
_state.ItemChanged+=OnItemChanged;
protected DomainObject(DomainObjectEventHandler onItemRemoved) : this()
{ ItemRemoved+=onItemRemoved; }
protected DomainObject(IdType id) : this() => SetId(id);
public Action SetDeleted =>_state.SetDeleted;
public TIdentity Identity { get;set; }
public virtual bool IsActionable =>_state.IsActionable;
private protected bool IsValidToInsert =>_id==0 && _state.IsNew;
private protected Action SetDirty { get { return _state.SetDirty; } }
CrudOperation IDataObject<IDomainObject>.Operation => (CrudOperation)((IObjectStateManaged)this).State;
ObjectStateManager IObjectStateManaged.State => _state;
protected void SetId(IdType id)
if(id.Equals(IEntityId.Empty)) return;
((IObjectStateManaged)this).State.SetNew(false);
protected virtual void OnItemRemoved(object sender)
WL($"DomainObject.OnItemRemoved: {sender.ToString()}");
ItemRemoved?.Invoke(this);
protected virtual void OnItemChanged(object sender)
WL($"DomainObject.OnItemChanged: {sender.ToString()}");
ItemChanged?.Invoke(this);
public override string ToString() => $"Id: {Id.ToString()}";
public record struct Aggregate<T>(IEnumerable<T> Items){}
public class DomainAggregate<T> : IDomainAggregate<T>, IEnumerable<T>, IEnumerable, IActionable<T>, IEmptyAggregateObject<T>
private ObjectStateManager _state=new();
public IList<T> Items {get;}=new List<T>();
public DomainAggregate(IEnumerable<T> items)=>AddItems(items);
public bool IsNew =>((IDomainAggregate<T>)this).IsNew;
public bool IsDirty =>((IDomainAggregate<T>)this).IsDirty;
public bool IsDeleted =>((IDomainAggregate<T>)this).IsDeleted;
public void Add( T item )
item.ItemRemoved+=((IDomainAggregate<T>)this).OnItemRemoved;
public void AddItems(IEnumerable<T> items) => items.For(item=>Add(item));
public void AddItems(params T [] items) => items.For(item=>Add(item));
public bool IsActionable =>IsNew || IsDirty || IsDeleted;
if(!Enumerable.TryGetNonEnumeratedCount(Items, out int count)) count=Items.Count();
public IEnumerator<T> GetEnumerator() =>Items.GetEnumerator();
IEnumerator<T> IEnumerable<T>.GetEnumerator() =>Items.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() =>Items.GetEnumerator();
public T this[int index]=>Items[index];
public class Person : DomainObject, IEntityObjectId<PersonId>, IDomainObject<Person>, IServiceObject<Person>, IDataObject<Person>, IBusinessObject<Person>, IActionable<Person>, IEmptyObject<Person>
private Value<string> _first, _last;
private PersonId _entityId=PersonId.Empty;
public Person() => (_first, _last) = ( new Value<string>(SetDirty), new Value<string>(SetDirty) );
public Person(IdType id, string first, string last) : base(id)
=> ( _first, _last ) = ( new Value<string>(first, SetDirty), new Value<string>(last, SetDirty) );
public PersonId EntityId => _entityId==PersonId.Empty ? _entityId=new PersonId(base.Id) : _entityId;
public string First { get=>_first; set=>_first.Set(value); }
public string Last { get=>_last; set=>_last.Set(value); }
bool IActionable<Person>.IsActionable=>true;
bool IActionable<Person>.IsValidToInsert=>base.IsValidToInsert && ( !String.IsNullOrWhiteSpace(First) && !String.IsNullOrWhiteSpace(Last) );
CrudOperation IDataObject<Person>.Operation=>(CrudOperation)((IObjectStateManaged)this).State;
void IEntityObjectId<PersonId>.SetId(PersonId id) { base.SetId(id.Id); _entityId=_entityId with {Id=id}; }
public override string ToString()=>base.ToString() + $", First: {First}, Last: {Last}";
public class Employee : Person, IEntityObjectId<EmployeeId>, IDomainObject<Employee>, IServiceObject<Employee>, IDataObject<Employee>, IBusinessObject<Employee>, IActionable<Employee>, IEmptyObject<Employee>
private Value<string> _title;
private EmployeeId _entityId= EmployeeId.Empty;
public Employee() => _title=new Value<string>(SetDirty);
public Employee(IdType id, string title, string first, string last) : base(id, first, last)
=> _title=new Value<string>(title, SetDirty);
public new EmployeeId EntityId =>_entityId==EmployeeId.Empty ? _entityId=new EmployeeId(base.Id) : _entityId;
public string Title { get=>_title; set=>_title.Set(value); }
bool IActionable<Employee>.IsActionable=>true;
bool IActionable<Employee>.IsValidToInsert=>((IActionable<Person>)this).IsValidToInsert && ( !String.IsNullOrWhiteSpace(Title) );
CrudOperation IDataObject<Employee>.Operation=>(CrudOperation)((IObjectStateManaged)this).State;
void IEntityObjectId<EmployeeId>.SetId(EmployeeId id) { base.SetId(id.Id); _entityId=_entityId with {Id=id}; }
public override string ToString()=> base.ToString() + $", Title: {Title} ";
public struct Age : IDomainObject, IDataObject<Age>, IBusinessObject<Age>, IServiceObject<Age>, IActionable<Age>, IEntityObjectId<AgeId>, IEntityId
public event DomainObjectEventHandler? ItemRemoved;
private AgeId _entityId=AgeId.Empty;
private Value<int> _value;
private ObjectStateManager _state=new();
public Age() => _value=new Value<int>(_state.SetDirty);
public Age(IdType id, int value)
((IEntityObjectId<AgeId>)this).SetId(new AgeId(id));
_value=new Value<int>(value, _state.SetDirty);
public AgeId EntityId =>_entityId==AgeId.Empty ? _entityId=new AgeId(Id) : _entityId;
public ObjectStateManager State =>_state;
public TIdentity Identity { get;set; }
public int Value {get=>_value;set=>_value.Set(value);}
public bool IsValidToInsert => Value!=0;
bool IActionable<Age>.IsValidToInsert => IsValidToInsert;
CrudOperation IDataObject<Age>.Operation=>(CrudOperation)((IObjectStateManaged)this).State;
void IEntityObjectId<AgeId>.SetId(AgeId id)
if(id.Equals(IEntityId.Empty)) return;
_entityId=_entityId with {Id=id};
((IObjectStateManaged)this).State.SetNew(false);
public class People : DomainAggregate<Person>
public People(IEnumerable<Person> people) : base (people){}
public class Employees : DomainAggregate<Employee>
public Employees(IEnumerable<Employee> employees) : base (employees){}
public enum Accessibility : byte
public enum CrudOperation : byte
public enum ObjectLifetime : byte
namespace Core.Dependencies
using DIM=Core.Dependencies.DependencyInversion.DependencyInversionMessage;
using Core.Collections.Generic;
using SCI=System.Collections.Immutable;
public ref struct DependencyOptions(ObjectLifetime lifetime=ObjectLifetime.Transient, bool enforceAssignability=true, bool enforceAbstractionToImplementationRelationship=false, object alias=null, Accessibility propertyAccessibilityInjected=Accessibility.AllButPublic, Func<dynamic>? factory=null)
public ObjectLifetime Lifetime=lifetime;
public bool EnforceAssignability=enforceAssignability;
public bool EnforceAbstractionToImplementationRelationship=enforceAbstractionToImplementationRelationship;
public object Alias=alias;
public Accessibility PropertyAccessibilityInjected=propertyAccessibilityInjected;
public Func<dynamic>? Factory {get;internal set;}=factory;
public DependencyOptions(DependencyOptions dependencyOptions) : this(dependencyOptions.Lifetime, dependencyOptions.EnforceAssignability, dependencyOptions.EnforceAbstractionToImplementationRelationship, dependencyOptions.Alias, dependencyOptions.PropertyAccessibilityInjected, dependencyOptions.Factory){}
public void Deconstruct(out ObjectLifetime lifetime, out bool enforceAssignability, out bool enforceAbstractionToImplementationRelationship, out object alias, out Accessibility propertyAccessibilityInjected, out Func<dynamic>? factory)
=> (lifetime, enforceAssignability, enforceAbstractionToImplementationRelationship, alias, propertyAccessibilityInjected, factory)=
(Lifetime, EnforceAssignability, EnforceAbstractionToImplementationRelationship, Alias, PropertyAccessibilityInjected, Factory);
public static implicit operator (ObjectLifetime Lifetime, bool EnforceAssignability, bool EnforceAbstractionToImplementationRelationship, object Alias, Accessibility PropertyAccessibilityInjected, Func<dynamic>? Factory) (DependencyOptions dependencyOptions)
=> (dependencyOptions.Lifetime, dependencyOptions.EnforceAssignability, dependencyOptions.EnforceAbstractionToImplementationRelationship, dependencyOptions.Alias, dependencyOptions.PropertyAccessibilityInjected, dependencyOptions.Factory);
public static implicit operator DependencyOptions ( (ObjectLifetime Lifetime, bool EnforceAssignability, bool EnforceAbstractionToImplementationRelationship, object Alias, Accessibility PropertyAccessibilityInjected, Func<dynamic>? Factory) dependencyOptions)
=> new (dependencyOptions.Lifetime, dependencyOptions.EnforceAssignability, dependencyOptions.EnforceAbstractionToImplementationRelationship, dependencyOptions.Alias, dependencyOptions.PropertyAccessibilityInjected, dependencyOptions.Factory);
public interface ISecuredDependencyInversion
public TIdentity Identity {get;}
public class SecureDependencyInversion(TIdentity identity)
private TIdentity _identity=identity;
public SecureDependencyInversion() : this(null)
public partial class DependencyInversion : System.IServiceProvider, IEnumerable, IEnumerable<KeyValuePair<Type, DependencyInversion.ValidatedDependency>>
private const string BACKING_PROPERTY_FIELD_NAME="__BACKINGFIELD";
internal enum DependencyInversionMessage : byte
AliasNotFound, AssignabilityViolation, AbstractionToImplementationViolation,
DuplicateAlias, DuplicateRegistration, IncorrectPassword,
IdenticalTypes, IsNotClass, IsValueType,
Locked, TypeNotFound, Unknown
public delegate Type AddTypeResolverDelegate(Type serviceType);
public delegate string AddTypeNameResolverDelegate(Type serviceType);
private object _password;
private static (ObjectLifetime Lifetime, bool EnforceAssignability, bool EnforceAbstractionToImplementationRelationship, object Alias, Accessibility PropertyAccessibilityInjected, Func<dynamic>? Factory)
_defaultDependencyOptions=new DependencyOptions();
public static DependencyInversion Global =>___global.Value;
private static Lazy<DependencyInversion> ___global =new Lazy<DependencyInversion>( ()=>new DependencyInversion() );
private static AddTypeResolverDelegate __addTypeResolver =type=>Global.DefaultAddTypeResolver(type);
private static AddTypeNameResolverDelegate __addTypeNameResolver =type=>type.Name.Substring(1);
private static ImmutableDictionary<Type, ValidatedDependency> __registrations =ImmutableDictionary<Type, ValidatedDependency>.Empty;
private static ImmutableDictionary<Type, IEnumerable<ValidatedDependency>> __registrationCollections =ImmutableDictionary<Type, IEnumerable<ValidatedDependency>>.Empty;
internal struct Exceptions
internal static Exception AliasNotFound => new ArgumentException("The alias name specified can not be found.");
internal static Exception AssignabilityViolation => new TypeAccessException("The source type can not be cast to the destination type, and EnforceAssignability flag is true; action prohibited.");
internal static Exception AbstractionToImplementationViolation
=> new TypeAccessException("The source type is not an abstraction (interface or abstract class), and EnforceAbstractionToImplementationRelationship flag is true; action prohibited.");
internal static Exception DuplicateAlias => new ArgumentException("The Alias specified is already used in another registration. Each alias must be unique to a specific single registration.");
internal static Exception DuplicateRegistration => new InvalidOperationException("The source type is already registered; duplicate registrations prohibited.");
internal static Exception IncorrectPassword => new ArgumentException("Incorrect password to unlock Dependency Injection component.");
internal static Exception IsNotClass => new InvalidOperationException("The destination type specific is not a class.");
internal static Exception IsValueType => new TypeAccessException("The destination type is a value type (struct); value types prohibited.");
internal static Exception IdenticalTypes => new InvalidOperationException("Both types are the same, and EnforceAbstractionToImplementationRelationship flag is true; action prohibited.");
internal static Exception Locked => new InvalidOperationException("The Dependency Inversion component is LOCKED. You can't add to it.");
internal static Exception TypeNotFound => new TypeAccessException("The type specified can not be found.");
internal static Exception TypeNotRegistered => new TypeAccessException("The type specified has not been registered for dependency inversion.");
internal static Exception Unknown => new ApplicationException("An unknown dependency inversion error occurred!!!");
internal static Exception CreateAggregate(IEnumerable<Exception> exceptions)=>new AggregateException(exceptions);
static DependencyInversion() {}
public DependencyInversion() {}
public DependencyInversion(IEnumerable<Dependency> dependencies) => addServices(dependencies);
public DependencyInversion(AddTypeResolverDelegate addTypeResolver) => __addTypeResolver=addTypeResolver;
public DependencyInversion(DependencyOptions defaultDependencyOptions)
=> setDefaultDependencyOptions(defaultDependencyOptions);
public void AddTransient([DN] Type serviceType, [DN] Type implementationType) => AddService(serviceType, implementationType, lifetime:ObjectLifetime.Transient);
public void AddTransient<TServiceType, TImplementationType>() => AddTransient(typeof(TServiceType), typeof(TImplementationType));
public void AddTransient<T>() => AddService(typeof(T), _defaultDependencyOptions);
public void AddScoped([DN] Type serviceType, [DN] Type implementationType) => AddService(serviceType, implementationType, lifetime:ObjectLifetime.Scoped);
public void AddScoped<TTo, TFrom>() => AddScoped(typeof(TTo), typeof(TFrom));
public void AddScoped<T>() => AddService(typeof(T), _defaultDependencyOptions with {Lifetime=ObjectLifetime.Scoped});
public void AddSingleton([DN] Type serviceType, [DN] Type implementationType) => AddService(serviceType, implementationType, lifetime:ObjectLifetime.Singleton);
public void AddSingleton<TServiceType, TImplementationType>() => AddSingleton(typeof(TServiceType), typeof(TImplementationType));
public void AddSingleton<T>() => AddService(typeof(T), _defaultDependencyOptions with {Lifetime=ObjectLifetime.Singleton});
public void AddService([DN] Type serviceType) => AddService(serviceType, _defaultDependencyOptions);
public void AddService([DN] Type serviceType, DependencyOptions options)
if(serviceType.IsAbstract || serviceType.IsInterface)
toType=__addTypeResolver(serviceType);
if(toType is null) throw Exceptions.TypeNotFound;
var dependency=new Dependency(serviceType:serviceType, implementationType:toType!, options);
if(!serviceType.IsAbstract) dependency.EnforceAbstractionToImplementationRelationship=false;
addService(dependency:dependency);
public void AddService<T>([DN] Func<T> factory) where T : class => AddService<T>(factory, _defaultDependencyOptions);
public void AddService<T>([DN] Func<T> factory, DependencyOptions options) where T : class
=> AddService<T, dynamic>( options with {Factory=factory} );
public void AddService<T>() => AddService(serviceType:typeof(T), _defaultDependencyOptions);
public void AddService<T>(DependencyOptions options) => AddService(serviceType:typeof(T), options);
public void AddService<TServiceType, TImplementationType>() => AddService( dependency:new Dependency( serviceType:typeof(TServiceType), implementationType:typeof(TImplementationType) ) );
public void AddService<TServiceType, TImplementationType>(ObjectLifetime lifetime) => AddService( dependency:new Dependency( serviceType:typeof(TServiceType), implementationType:typeof(TImplementationType), new DependencyOptions(lifetime:lifetime) ));
public void AddService<TServiceType, TImplementationType>(DependencyOptions options)=> addService(new Dependency(typeof(TServiceType), typeof(TImplementationType), options));
public void AddService([DN]Type serviceType, [DN] Type implementationType, ObjectLifetime lifetime=ObjectLifetime.Transient)
=> AddService( dependency:new Dependency( serviceType:serviceType, implementationType:implementationType, new DependencyOptions(lifetime:lifetime) ) );
public void AddService([DN]Type serviceType, [DN] Type implementationType, DependencyOptions options) => AddService(dependency:new Dependency(serviceType, implementationType, options));
public void AddService([DN]Dependency dependency) =>addService(dependency);
public void AddService([DN] string serviceTypeFullName, [DN] string implementationTypeFullName, DependencyOptions options=default)
=> AddService(dependency:new Dependency(Type.GetType(serviceTypeFullName, true, true), Type.GetType(implementationTypeFullName, true, true), options));
public bool TryAddTransient([DN] Type serviceType, [DN] Type implementationType) => TryAddService(serviceType, implementationType, lifetime:ObjectLifetime.Transient);
public bool TryAddTransient<TServiceType, TImplementationType>() => TryAddTransient(typeof(TServiceType), typeof(TImplementationType));
public bool TryAddTransient<T>() => TryAddService(typeof(T), _defaultDependencyOptions);
public bool TryAddScoped([DN] Type serviceType, [DN] Type implementationType) => TryAddService(serviceType, implementationType, lifetime:ObjectLifetime.Scoped);
public bool TryAddScoped<TTo, TFrom>() => TryAddScoped(typeof(TTo), typeof(TFrom));
public bool TryAddScoped<T>() => TryAddService(typeof(T), _defaultDependencyOptions with {Lifetime=ObjectLifetime.Scoped});
public bool TryAddSingleton([DN] Type serviceType, [DN] Type implementationType)=> TryAddService(serviceType, implementationType, lifetime:ObjectLifetime.Singleton);
public bool TryAddSingleton<TServiceType, TImplementationType>() => TryAddSingleton(typeof(TServiceType), typeof(TImplementationType));
public bool TryAddSingleton<T>() => TryAddService(typeof(T), _defaultDependencyOptions with {Lifetime=ObjectLifetime.Singleton});
public bool TryAddService([DN] Type serviceType) => TryAddService(serviceType, _defaultDependencyOptions);
public bool TryAddService([DN] Type serviceType, DependencyOptions options)
if(serviceType.IsAbstract || serviceType.IsInterface)
toType=__addTypeResolver(serviceType);
if(toType is null) throw Exceptions.TypeNotFound;
var dependency=new Dependency(serviceType:serviceType, implementationType:toType!, options);
if(!serviceType.IsAbstract) dependency.EnforceAbstractionToImplementationRelationship=false;
return tryAddService(dependency:dependency);
public bool TryAddService<T>([DN] Func<T> factory) where T : class => TryAddService<T>(factory, _defaultDependencyOptions);
public bool TryAddService<T>([DN] Func<T> factory, DependencyOptions options) where T : class
=> TryAddService<T, dynamic>( options with {Factory=factory} );
public bool TryAddService<T>() => TryAddService(serviceType:typeof(T), _defaultDependencyOptions);
public bool TryAddService<T>(DependencyOptions options) => TryAddService(serviceType:typeof(T), options);
public bool TryAddService<TServiceType, TImplementationType>() => TryAddService( dependency:new Dependency( serviceType:typeof(TServiceType), implementationType:typeof(TImplementationType) ) );
public bool TryAddService<TServiceType, TImplementationType>(ObjectLifetime lifetime) => TryAddService( dependency:new Dependency( serviceType:typeof(TServiceType), implementationType:typeof(TImplementationType), new DependencyOptions(lifetime:lifetime) ));
public bool TryAddService<TServiceType, TImplementationType>(DependencyOptions options) => tryAddService(new Dependency(typeof(TServiceType), typeof(TImplementationType), options));
public bool TryAddService([DN]Type serviceType, [DN] Type implementationType, ObjectLifetime lifetime=ObjectLifetime.Transient)
=> TryAddService( dependency:new Dependency( serviceType:serviceType, implementationType:implementationType, new DependencyOptions(lifetime:lifetime) ) );
public bool TryAddService([DN]Type serviceType, [DN] Type implementationType, DependencyOptions options) => TryAddService(dependency:new Dependency(serviceType, implementationType, options));
public bool TryAddService([DN]Dependency dependency) => tryAddService(dependency);
public bool TryAddService([DN] string serviceTypeFullName, [DN] string implementationTypeFullName, DependencyOptions options=default)
=> TryAddService(dependency:new Dependency(Type.GetType(serviceTypeFullName, true, true), Type.GetType(implementationTypeFullName, true, true), options));
public void AddServices([DN] (Type serviceType, Type implementationType) [] dependencies)
for(var c=0;c<dependencies.Length;c++)
AddService(dependencies[c].serviceType, dependencies[c].implementationType);
public void AddServices([DN]params Dependency [] dependencies) => addServices(dependencies);
public void AddServices([DN]IEnumerable<Dependency> dependencies) => addServices(dependencies);
public void AddServices([DN] Type serviceType, Type [] implementationTypes)
public bool TryAddServices([DN] (Type serviceType, Type implementationType) [] dependencies)
for(var c=0;c<dependencies.Length;c++)
if(!TryAddService(dependencies[c].serviceType, dependencies[c].implementationType)) return false;
public bool TryAddServices([DN]params Dependency [] dependencies) => tryAddServices(dependencies);
public bool TryAddServices([DN]IEnumerable<Dependency> dependencies) => tryAddServices(dependencies);
public virtual Type DefaultAddTypeResolver([DN] Type serviceType, AddTypeNameResolverDelegate fromTypeToTargetTypeNameStringFunction=null)
if(fromTypeToTargetTypeNameStringFunction is not null) DependencyInversion.TypeNameResolver=fromTypeToTargetTypeNameStringFunction;
string toTypeName=string.Concat(DependencyInversion.TypeNameResolver?.Invoke(serviceType),"");
var toTypeFullName=serviceType.FullName!.Replace(serviceType.Name, toTypeName);
if(tryGetType(toTypeFullName, out Type? toType)) return toType;
if(toType is null) throw Exceptions.TypeNotFound;
public TServiceType GetService<TServiceType>([DN] Type serviceType)=>(TServiceType?)GetService(serviceType:serviceType);
public TServiceType GetService<TServiceType>()
var requestedKeyType=typeof(TServiceType);
ValidatedDependency? registeredDependency=findRegisteredType(requestedKeyType);
if(registeredDependency is null) throw Exceptions.TypeNotRegistered;
var returnedService=GetService(serviceType:requestedKeyType);
return (TServiceType)returnedService!;
public object GetService([DN]object alias)
ValidatedDependency? result=__registrations.Values.FirstOrDefault(r=>r.Alias==alias);
if(result is null) throw Exceptions.AliasNotFound;
return GetService(serviceType:result?.ServiceType!);
public object GetService([DN] string serviceTypeFullName
var serviceType=Type.GetType(serviceTypeFullName, false, true);
if(serviceType is null) throw Exceptions.TypeNotFound;
return GetService(serviceType);
public object GetService([DN] Type serviceType)
ValidatedDependency? validatedDependency=findRegisteredType(serviceType!);
if(validatedDependency is null) throw Exceptions.TypeNotRegistered;
return getService(validatedDependency);
public bool IsRegistered([DN] Type type) => __registrations.ContainsKey(type);
public void Lock([Optional] object password) => (_isLocked, _password)=(true, password);
public void Unlock([Optional] object password)
_isLocked=password==_password;
if(_isLocked) throw Exceptions.IncorrectPassword;
public object this[[DN] Type serviceType]
if(!__registrations.TryGetValue(serviceType, out ValidatedDependency? validatedDependency)) throw Exceptions.TypeNotFound;
return GetService(validatedDependency!);
public object this[[DN] object alias] => GetService(__registrations.Values.FirstOrDefault(d=>d.Alias==alias)!);
public IEnumerator<KeyValuePair<Type, ValidatedDependency>> GetEnumerator() =>__registrations.GetEnumerator();
IEnumerator<KeyValuePair<Type, ValidatedDependency>> IEnumerable<KeyValuePair<Type, ValidatedDependency>>.GetEnumerator() =>__registrations.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() =>__registrations.GetEnumerator();
if(_length==0 && !Enumerable.TryGetNonEnumeratedCount(__registrations, out _length)) _length=__registrations.Count();
public static AddTypeResolverDelegate TypeResolver {get=>__addTypeResolver;set=>__addTypeResolver=value;}
public static AddTypeNameResolverDelegate TypeNameResolver{get=>__addTypeNameResolver;set=>__addTypeNameResolver=value;}
private void addService([DN]Dependency dependency)
if(_isLocked) throw Exceptions.Locked;
var validatedDependency=validateDependencyBeforeAdd(dependency);
__registrations=__registrations.Add(dependency.ServiceType, validatedDependency);
private void addServices([DN]IEnumerable<Dependency> dependencies)
=> dependencies.For(dependency=>addService(dependency));
private object?[] createParameterValues([DN] TypeInfo typeInfo)
=> typeInfo.ParameterObjects=createConstructorParametersDefaultValues(typeInfo, abstractTypeCreationFactory:p=>GetService(p), typeInfo.ConstructorIndex);
public object?[] createConstructorParametersDefaultValues([DN] TypeInfo typeInfo, [Optional] Func<Type, object> abstractTypeCreationFactory, int constructorIndex=0)
if(!typeInfo.hasConstructor) return Array.Empty<object>();
return !typeInfo.hasConstructorParameters ? Array.Empty<object>() : createParametersDefaultValues(parameters:typeInfo.ConstructorParameters ?? new ParameterInfo[0], abstractTypeCreationFactory);
public object?[] createMethodParametersDefaultValues([DN] MethodInfo method, [Optional] Func<Type, object> abstractTypeCreationFactory)
var parameters=method.GetParameters();
if(!Enumerable.TryGetNonEnumeratedCount(parameters, out int count)) count=parameters.Count();
return parameters is null || count==0 ? Array.Empty<object>() : createParametersDefaultValues(parameters:parameters, abstractTypeCreationFactory);
public object?[] createParametersDefaultValues(ParameterInfo [] parameters, [Optional] Func<Type, object> abstractTypeCreationFactory)
if(parameters is null || parameters.Length==0) return Array.Empty<object>();
var returned=new object?[parameters.Length];
for(var c=0;c<parameters.Length;c++)
TypeInfo parameterTypeInfo=new TypeInfo(parameters[c].ParameterType);
if (parameterTypeInfo.IsAbstract && abstractTypeCreationFactory is not null)
returned[c]=abstractTypeCreationFactory?.Invoke(parameterTypeInfo.Type);
else if (!parameterTypeInfo.IsAbstract)
returned[c]=System.Activator.CreateInstance(parameterTypeInfo.Type, createConstructorParametersDefaultValues(parameterTypeInfo));
public object createType(TypeInfo implementationTypeInfo, [Optional] Func<Type, object> abstractTypeCreationFactory, [Optional, DPV(0)] int constructorIndex, [Optional] params object [] parameterValues)
object? returned=default;
if(parameterValues is null || parameterValues.Length==0)
returned=System.Activator.CreateInstance(implementationTypeInfo.Type, createConstructorParametersDefaultValues(implementationTypeInfo, abstractTypeCreationFactory, constructorIndex));
else returned=System.Activator.CreateInstance(implementationTypeInfo.Type, parameterValues);
private ValidatedDependency findRegisteredType([DN] Type serviceType)
_=__registrations.TryGetValue(serviceType, out ValidatedDependency? result);
private object getService([DN] ValidatedDependency validatedDependency, [Optional] params object [] parameterValues)
if(validatedDependency!.Lifetime==ObjectLifetime.Singleton && validatedDependency!.hasSingletonInstance) return validatedDependency.SingletonInstance;
else if(validatedDependency!.Lifetime==ObjectLifetime.Scoped && validatedDependency!.hasScopedInstance) return validatedDependency.ScopedInstance;
if(validatedDependency.hasFactory)
returned=validatedDependency.Factory?.Invoke();
if(returned is null) throw Exceptions.TypeNotFound;
Hi($"NOT Factory {validatedDependency.ToString()}");
returned=createType(validatedDependency.ImplementationTypeInfo, abstractType=>GetService(abstractType), validatedDependency.ImplementationTypeInfo.ConstructorIndex, parameterValues);
setProperties(returned!);
if(validatedDependency?.Lifetime==ObjectLifetime.Singleton) ((Dependency)validatedDependency).SingletonInstance=returned!;
else if(validatedDependency?.Lifetime==ObjectLifetime.Scoped) ((Dependency)validatedDependency).ScopedInstance=returned!;
private void setDefaultDependencyOptions([DN] DependencyOptions dependencyOptions)
=> _defaultDependencyOptions=dependencyOptions;
private void setProperties([DN] object objectToSet)
from field in objectToSet.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)
from rtype in __registrations.Values
let FieldType = field.FieldType
let currentValue = field.GetValue(objectToSet)
let ToType = rtype.ImplementationType
let IsNull = currentValue is null
let IsPrivate = field.IsPrivate
let IsPrivateProtected = field.IsFamilyAndAssembly
let IsProtectedInternal = field.IsFamilyOrAssembly
let IsInternal = field.IsAssembly
let IsPublic = field.IsPublic
let IsBackingProperty = field.Name.ToUpper().Contains(BACKING_PROPERTY_FIELD_NAME)
let FieldAccessibility = rtype.FieldAccessibilityInjected
FieldType.FullName==rtype.ServiceType.FullName
( IsPrivate && FieldAccessibility.HasFlag(Accessibility.Private))
|| ( IsPrivateProtected && FieldAccessibility.HasFlag(Accessibility.PrivateProtected))
|| ( IsProtectedInternal && FieldAccessibility.HasFlag(Accessibility.ProtectedInternal))
|| ( IsInternal && FieldAccessibility.HasFlag(Accessibility.Internal))
|| ( IsPublic && FieldAccessibility.HasFlag(Accessibility.Public))
select new {Field, ToType}
for(var c=0;c<properties.Length;c++)
properties[c].Field.SetValue(objectToSet, createType(new TypeInfo(properties[c].ToType)));
private bool tryAddService([DN]Dependency dependency)
bool result=true; try { addService(dependency); } catch { result=false; } return result;
private bool tryAddServices([DN] IEnumerable<Dependency> dependencies)
bool result=true; try { addServices(dependencies); } catch { result=false; } return result;
private bool tryGetService([DN] ValidatedDependency validatedDependency, [MaybeNull] out object returned)
returned=null; bool result=true; try { returned=getService(validatedDependency); } catch { result=false; } return result;
private bool tryGetServices([DN] ValidatedDependency validatedDependency, [MaybeNull] out IEnumerable<object> returned)
private ValidatedDependency validateDependencyBeforeAdd([DN] Dependency dependency)
var exceptions=new List<Exception>();
AggregateException? aggregateException=null;
if(!Enumerable.TryGetNonEnumeratedCount(__registrations, out int count)) count=__registrations.Count();
if(__registrations.ElementAt(c).Value.ServiceType.FullName==dependency.ServiceType.FullName)
exceptions.Add(Exceptions.DuplicateRegistration);
{ validateDependency(dependency); }
catch (AggregateException e)
if(aggregateException is not null) exceptions.AddRange(aggregateException.InnerExceptions);
if(!Enumerable.TryGetNonEnumeratedCount(exceptions, out count)) count=exceptions.Count();
if(count>0) throw Exceptions.CreateAggregate(exceptions);
return new ValidatedDependency(dependency);
private ValidatedDependency validateDependency([DN] Dependency dependency)
var exceptions=new List<Exception>();
if(dependency.EnforceAssignability && !dependency.IsAssignable)
exceptions.Add(Exceptions.AssignabilityViolation);
if(dependency.EnforceAbstractionToImplementationRelationship && !dependency.ServiceType.IsInterface && !dependency.ServiceType.IsAbstract)
exceptions.Add(Exceptions.AbstractionToImplementationViolation);
if(dependency.EnforceAbstractionToImplementationRelationship && dependency.ServiceType.FullName==dependency.ImplementationType.FullName)
exceptions.Add(Exceptions.IdenticalTypes);
if(!dependency.ImplementationType.IsClass)
exceptions.Add(Exceptions.IsNotClass);
if(dependency.ImplementationType.IsValueType)
exceptions.Add(Exceptions.IsValueType);
if(!Enumerable.TryGetNonEnumeratedCount(exceptions, out int count)) count=exceptions.Count();
if(count>0) throw Exceptions.CreateAggregate(exceptions);
return new ValidatedDependency(dependency);
private bool tryGetType([DN] string typeName,[MaybeNullWhen(false)] [NotNullWhen(true)] out Type? target)
target=Type.GetType(typeName, false, true);
return target is not null;
public class TypeInfo<T> : TypeInfo
public TypeInfo() : base(typeof(T)) {}
public TypeInfo(int constructorIndex) : base(typeof(T), constructorIndex) {}
internal readonly ConstructorInfo? Constructor;
internal readonly ConstructorInfo[]? Constructors;
internal readonly ParameterInfo[]? ConstructorParameters;
private object?[]? _parameterObjects;
private string? _namespace;
private bool _hasConstructor, _hasConstructorParameters, _isAbstract, _isInterface;
private int _constructorIndex;
internal readonly Type Type;
private static ImmutableDictionary<Type, TypeInfo> _cache=new Dictionary<Type, TypeInfo>().ToImmutableDictionary();
public TypeInfo([DN] System.Type type) : this (type, 0) {}
public TypeInfo([DN] System.Type type, int constructorIndex)
_constructorIndex=constructorIndex;
(_isAbstract, _isInterface)=(type.IsAbstract, type.IsInterface);
if(!_cache.ContainsKey(type))
_cache=_cache.Add(type,this);
Constructors=type.GetConstructors();
Constructor=Constructors?[ConstructorIndex] ?? Constructors?.First();
ConstructorParameters=Constructor?.GetParameters()?.ToArray();
ParameterObjects=new object[ConstructorParameters is null ? 0 : ConstructorParameters.Length];
_hasConstructor=Constructor is not null;
_hasConstructorParameters=ConstructorParameters is not null && ConstructorParameters.Length>0;
_namespace=type?.FullName?.Replace(type.Name!, "");
var cachedTypeInfo=_cache[type];
(Constructor, Constructors, ConstructorParameters, _parameterObjects, _namespace, _hasConstructor, _hasConstructorParameters)
=(cachedTypeInfo.Constructor, cachedTypeInfo.Constructors, cachedTypeInfo.ConstructorParameters, cachedTypeInfo.ParameterObjects, cachedTypeInfo.Namespace, cachedTypeInfo.hasConstructor, cachedTypeInfo.hasConstructorParameters);
internal object?[]? ParameterObjects {get=>_parameterObjects;set=>_parameterObjects=value;}
internal string? Namespace => _namespace;
internal bool hasConstructor => _hasConstructor;
internal bool hasConstructorParameters => _hasConstructorParameters;
public int ConstructorIndex {get;set;}=0;
public bool IsAbstract => _isAbstract;
public bool IsInterface => _isInterface;
public static bool IsTypeCached(Type type) => _cache.ContainsKey(type);
public class Dependency<TFrom, TTo>() : Dependency(typeof(TFrom), typeof(TTo));
public class Dependency([DN] Type serviceType, [DN] Type implementationType)
[ThreadStatic, MaybeNull]
private static object _scopedInstance;
private static object _singletonInstance;
private TypeInfo _implementationTypeInfo=new TypeInfo(implementationType);
private TypeInfo _serviceTypeInfo=new TypeInfo(serviceType);
private bool _isAssignable=serviceType.IsAssignableFrom(implementationType);
public Dependency([DN] Type serviceType, [DN] Type implementationType, DependencyOptions options) : this(serviceType, implementationType)
=> (Lifetime, EnforceAssignability, EnforceAbstractionToImplementationRelationship, Alias, FieldAccessibilityInjected, Factory) = options;
public Dependency([DN] Type serviceType, [DN] Type implementationType, ObjectLifetime lifetime) : this(serviceType,implementationType)
=> (Lifetime, FromHashCode)=(lifetime, serviceType.GetHashCode());
public Dependency([DN] TypeInfo serviceTypeInfo, [DN] TypeInfo implementationTypeInfo, ObjectLifetime lifetime) : this(serviceTypeInfo.Type, implementationTypeInfo.Type)
=> (_serviceTypeInfo, _implementationTypeInfo, Lifetime, FromHashCode)=(serviceTypeInfo, implementationTypeInfo, lifetime, serviceTypeInfo.Type.GetHashCode());
public Type ServiceType =>serviceType;
public Type ImplementationType =>implementationType;
public TypeInfo ServiceTypeInfo =>_serviceTypeInfo;
public TypeInfo ImplementationTypeInfo =>_implementationTypeInfo;
public object Alias {get;set;}
public ObjectLifetime Lifetime {get;set;}=ObjectLifetime.Transient;
public bool EnforceAssignability {get;set;}=true;
public bool EnforceAbstractionToImplementationRelationship {get;set;}=true;
public Accessibility FieldAccessibilityInjected {get;set;}=Accessibility.AllButPublic;
[property: MaybeNull][AllowNull]
public Func<object> Factory {get;set;}
internal object ScopedInstance {get=>_scopedInstance;set=>_scopedInstance=value;}
internal object SingletonInstance {get=>_singletonInstance;set=>_singletonInstance=value;}
internal ConstructorInfo Constructor => ImplementationType.GetConstructors()?.First()!;
internal ParameterInfo[]? ConstructorParameters => ImplementationTypeInfo.ConstructorParameters;
internal object?[]? ParameterObjects {get => ImplementationTypeInfo.ParameterObjects;set => ImplementationTypeInfo.ParameterObjects=value;}
internal bool hasSingletonInstance => SingletonInstance is not null;
internal bool hasScopedInstance => ScopedInstance is not null;
internal bool hasFactory => Factory is not null;
internal bool hasConstructor => ImplementationTypeInfo.hasConstructor;
internal bool hasConstructorParameters => ImplementationTypeInfo.hasConstructorParameters;
public bool IsAssignable => _isAssignable;
public int HashCode => ServiceType.GetHashCode();
public int FromHashCode {get;init;}
public override string ToString() =>$"ServiceType: {ServiceType}, ImplementationType: {ImplementationType}, hasCtor: {hasConstructor}, hasConstructorParameters: {hasConstructorParameters}, hasFactory: {hasFactory} ";
public sealed class ValidatedDependency(Dependency dependency) : Dependency(dependency.ServiceType, dependency.ImplementationType, new DependencyOptions(dependency.Lifetime, dependency.EnforceAssignability, dependency.EnforceAbstractionToImplementationRelationship, dependency.Alias, dependency.FieldAccessibilityInjected, dependency.Factory) );
public record struct CallerInfo(str Name="", int Line=0, str Path="")
public void Deconstruct(out str name, out int line, out str path)=>(name, line, path)=(Name, Line, Path);
public (string Key, object Value) [] ToArray() => [ ("Name", Name), ("Line", Line) , ("Path", Path) ];
public Exception UpdateExceptionData(Exception exception)
{ ( exception.Data["Name"], exception.Data["Line"], exception.Data["Path"] ) = ( Name, Line, Path); return exception; }
public Exception UpdateExceptionSource(Exception exception)
{ exception.Source=ToString(); return exception; }
public Exception UpdateException(Exception exception) => UpdateExceptionSource(UpdateExceptionData(exception));
public string ToString(string format="CallerInfo: {CallerName={Name}, CallerLineNumber={Line}, CallerFilePath={Path})")
=> format.Replace("{Name}", Name).Replace("{Line}", Line.ToString()).Replace("{Path}", Path);
public override string ToString()
=> ToString("CallerInfo: (CallerName={Name},CallerLineNumber={Line},CallerFilePath={Path})");
namespace Core.ErrorHandling.Exceptions.Custom
public class PebkacException(string message="Please inform the Help Desk that there's a problem in your chair.") : Exception(message);
public class Id10tException(string message="Please inform your boss that you keep getting an ID 10 T error, and that he might want to remedidate.") : Exception(message);
public class UnknownException([Optional] string message) : Exception(message);
public class PasswordException([Optional] string message) : Exception(message);
namespace Core.Collections.Generic
public enum DictionaryType : byte
{ Concurrent=1, Frozen=2, Immutable=3, Ordered=4, ReadOnly=5, Regular=0, Sorted=6 }
public class EnumKeyedImmutableDictionary<TEnum, TValue>(IDictionary<TEnum, TValue> items, bool isFrozenDictionary=false) : ImmutableOrFrozenDictionary<TEnum, TValue>(items, isFrozenDictionary), IEnumerable<KeyValuePair<TEnum, TValue>>, IEnumerable
where TEnum : notnull, System.Enum
public EnumKeyedImmutableDictionary(ReadOnlySpan<KeyValuePair<TEnum, TValue>> items, bool isFrozenDictionary=false) : this(items.ToArray(), isFrozenDictionary) {}
public EnumKeyedImmutableDictionary(KeyValuePair<TEnum, TValue> [] items, bool isFrozenDictionary=false) : this(items.ToDictionary(), isFrozenDictionary) {}
public class ImmutableOrFrozenDictionary<TKey, TValue>(IDictionary<TKey, TValue> items, bool isFrozenDictionary=false)
: IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable
private int _count=items.Count();
private ExpandoObject expando=new ExpandoObject();
private protected IDictionary<TKey, TValue> _items=isFrozenDictionary ? items.ToFrozenDictionary() : items.ToImmutableDictionary();
public ImmutableOrFrozenDictionary(ReadOnlySpan<KeyValuePair<TKey, TValue>> items, bool isFrozenDictionary=false) : this(items.ToArray(), isFrozenDictionary) {}
public ImmutableOrFrozenDictionary(KeyValuePair<TKey, TValue> [] items, bool isFrozenDictionary=false) : this(items.ToDictionary(), isFrozenDictionary) {}
public bool Contains(KeyValuePair<TKey, TValue> kvp) =>_items.Contains(kvp);
public bool ContainsKey(TKey key) => _items.ContainsKey(key);
public void Freeze() => ( _items, IsFrozen )=(IsFrozen ? _items : _items.ToFrozenDictionary(), true);
public void Thaw() => ( _items, IsFrozen )=(!IsFrozen ? _items : _items.ToImmutableDictionary(), false);
public bool TryAdd([DN] TKey key, [DN] TValue value)
bool result=!IsFrozen && _items.TryAdd(key, value);
public bool TryForceAdd([DN] TKey key, [DN] TValue value)
if(!IsFrozen) result=TryAdd(key, value);
(IsFrozen, _items)=(false, _items.ToImmutableDictionary());
result=TryAdd(key, value);
(IsFrozen, _items)=(true, _items.ToFrozenDictionary());
public bool TryGetValue([DN]TKey key, [MaybeNullWhen(false), NotNullWhen(true)] out TValue value) => _items.TryGetValue(key, out value!);
public ExpandoObject ToExpando()
IDictionary<string, object> iDic=expando;
if(!Enumerable.TryGetNonEnumeratedCount(_items, out int count)) count=_items.Count();
var span=CollectionsMarshal.AsSpan<KeyValuePair<TKey, TValue>>(_items.ToList());
ref var reference=ref MemoryMarshal.GetReference(span);
for(var c=0;c<@count;c++)
var i=Unsafe.Add(ref reference, c);
iDic.Add(i.Key.ToString(), i.Value);
public int Count => _count;
public bool IsFrozen {get; private set;}=isFrozenDictionary;
public bool IsReadOnly => IsFrozen;
public ICollection<TKey> Keys => _items.Keys;
public ICollection<TValue> Values => _items.Values;
public TValue this[int index] => _items.ElementAt(index).Value;
public TValue this[TKey key] => _items[key];
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() => _items.GetEnumerator();
IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator() => _items.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => _items.GetEnumerator();
public static implicit operator Dictionary<TKey, TValue>(ImmutableOrFrozenDictionary<TKey, TValue> @this) => @this._items.ToDictionary();
public static explicit operator ExpandoObject(ImmutableOrFrozenDictionary<TKey, TValue> @this) => @this.ToExpando();
internal static class IdManager
private static int _lastId;
public static int GetId(ref int id)
newId = Interlocked.Increment(ref _lastId);
} while (newId.Equals(0));
Interlocked.CompareExchange(ref id, newId, 0);
namespace Core.Common.Helpers
using Core.Collections.Generic;
public class MessageBuilder<TMessageKey>(IDictionary<TMessageKey, string> messages)
: ImmutableOrFrozenDictionary<TMessageKey, string>(messages)
where TMessageKey : notnull
public MessageBuilder(ReadOnlySpan<KeyValuePair<TMessageKey, string>> items) : this(items.ToArray().ToImmutableDictionary()){}
public MessageBuilder( (TMessageKey key, string value) [] items)
: this(items.For(m=>KeyValuePair.Create<TMessageKey, string>(m.key, m.value))) {}
public new string this[TMessageKey key] => base[key];
public string Create(TMessageKey key, [Optional] params object[] interpolationValues)
=> string.Format(base.ContainsKey(key) ? base[key] : $"{this.GetType().Name} (key: {key}) not found.", (interpolationValues is null ? Array.Empty<object>() : interpolationValues) );
namespace Core.ErrorHandling.Exceptions
using Core.ErrorHandling.Exceptions.Custom;
public delegate Exception CustomExceptionFactoryDelegate();
public enum CommonExceptionType : byte { Access, Aggregate, Application, Argument, ArgumentNull, ArgumentOutOfRange, IndexOutOfRange, NotFound, NullReference, Operation, Type, Unknown }
public record ExceptionInfo(string message, Type? exceptionType=null, Func<string, Exception>? factory=null);
public class CommonException
private CommonExceptionType _commonExceptionType;
public CommonException(CommonExceptionType commonExceptionType, [Optional] string message)
=> (_message, _commonExceptionType)=(message, commonExceptionType);
public Exception this[CommonExceptionType commonExceptionType, [Optional] string message]=>Create(commonExceptionType, message);
public static Exception Create(CommonExceptionType commonExceptionType, [Optional] string message) => commonExceptionType switch
CommonExceptionType.Access => new AccessViolationException(message),
CommonExceptionType.Aggregate => new AggregateException(message),
CommonExceptionType.Application => new ApplicationException(message),
CommonExceptionType.Argument => new ArgumentException(message),
CommonExceptionType.ArgumentNull => new ArgumentNullException(message),
CommonExceptionType.ArgumentOutOfRange => new ArgumentOutOfRangeException(message),
CommonExceptionType.IndexOutOfRange => new IndexOutOfRangeException(message),
CommonExceptionType.NotFound => new ArgumentException(message),
CommonExceptionType.NullReference => new NullReferenceException(message),
CommonExceptionType.Operation => new InvalidOperationException(message),
CommonExceptionType.Type => new TypeAccessException(message),
CommonExceptionType.Unknown => new UnknownException(message),
_ => new ApplicationException(message)
public static Exception Create(CommonExceptionType commonExceptionType, [Optional] string message, [Optional] IEnumerable<object> interpolationValues)
=> Create(commonExceptionType, string.Format(string.Concat(message, string.Empty), interpolationValues));
public static Exception Create(CommonExceptionType commonExceptionType, [Optional] string message, [Optional] params object[] interpolationValues)
=> Create(commonExceptionType, string.Format(string.Concat(message, string.Empty), interpolationValues));
public static AggregateException CreateAggregate(Exception innerException) => CreateAggregate([innerException]);
public static AggregateException CreateAggregate(IEnumerable<Exception> innerExceptions) => new AggregateException(innerExceptions);
public static void Throw(CommonExceptionType commonExceptionType, [Optional] string message, [Optional] params object[] interpolationValues)
=> Create(commonExceptionType, message, interpolationValues);
public static void ThrowAggregate(Exception innerException)=>CreateAggregate(innerException);
public static void ThrowAggregate(IEnumerable<Exception> innerExceptions)=>CreateAggregate(innerExceptions);
public static AccessViolationException Access => new AccessViolationException();
public static AggregateException Aggregate => new AggregateException();
public static ApplicationException Application => new ApplicationException();
public static ArgumentException Argument => new ArgumentException();
public static ArgumentNullException ArgumentNull => new ArgumentNullException();
public static ArgumentOutOfRangeException ArgumentOutOfRange => new ArgumentOutOfRangeException();
public static IndexOutOfRangeException IndexOutOfRange => new IndexOutOfRangeException();
public static InvalidOperationException Operation => new InvalidOperationException();
public static NullReferenceException NullReference => new NullReferenceException();
public static TypeAccessException Type => new TypeAccessException();
public static UnknownException Unknown => new UnknownException();
public interface IBuilder<TKey>
public Exception Create(TKey key, [Optional] IEnumerable<object> interpolationValues, [CallerMemberName] in str callerName="", [CallerLineNumber]in int callerLineNumber=0, [CallerFilePath]in str callerFilePath="");
public AggregateException CreateAggregate(Exception innerException);
public AggregateException CreateAggregate(IEnumerable<Exception> innerExceptions);
public bool HasKey(TKey key);
public void Throw(TKey key, [Optional] IEnumerable<object> interpolationValues, [CallerMemberName] in str callerName="", [CallerLineNumber]in int callerLineNumber=0, [CallerFilePath]in str callerFilePath="");
public void ThrowAggregate(Exception innerException);
public void ThrowAggregate(IEnumerable<Exception> innerExceptions);
public abstract class BuilderBase<TKey, TValue>
private protected BuilderBase(IDictionary<TKey, TValue> xrefs, [AllowNull] bool includeExtendedInfo=true)
(Xrefs, _includeExtendedInfo)=(new(xrefs), includeExtendedInfo);
private protected const string KEYNOTFOUND="TMessageEnumKey value not found in ExceptionBuilder<TMessageEnumKey>";
protected internal readonly Core.Collections.Generic.ImmutableOrFrozenDictionary<TKey, TValue> Xrefs;
protected internal readonly bool? _includeExtendedInfo;
public AggregateException CreateAggregate(Exception innerException) => CreateAggregate([innerException]);
public AggregateException CreateAggregate(IEnumerable<Exception> innerExceptions) => new AggregateException(innerExceptions);
public void ThrowAggregate(Exception innerException) => CreateAggregate([innerException]);
public void ThrowAggregate(IEnumerable<Exception> innerExceptions) => CreateAggregate(innerExceptions);
public abstract Exception Create(TKey key, [Optional] IEnumerable<object> interpolationValues, [CallerMemberName] in str callerName="", [CallerLineNumber]in int callerLineNumber=0, [CallerFilePath]in str callerFilePath="");
public bool HasKey(TKey key)=>Xrefs.ContainsKey(key);
public abstract void Throw(TKey key, [Optional] IEnumerable<object> interpolationValues, [CallerMemberName] in str callerName="", [CallerLineNumber]in int callerLineNumber=0, [CallerFilePath]in str callerFilePath="");
public class CommonExceptionBuilder(IDictionary<CommonExceptionType, string> commonExceptionTypeToMessageXref=null, bool includeExtendedInfo=true)
: BuilderBase<CommonExceptionType, string>(commonExceptionTypeToMessageXref, includeExtendedInfo), IBuilder<CommonExceptionType>
public override Exception Create(CommonExceptionType commonExceptionType, [Optional] IEnumerable<object> interpolationValues,
[CallerMemberName] in str callerName="", [CallerLineNumber]in int callerLineNumber=0, [CallerFilePath]in str callerFilePath="" )
var e=CommonException.Create(commonExceptionType, Xrefs[commonExceptionType], interpolationValues);
return includeExtendedInfo ? new CallerInfo(callerName, callerLineNumber, callerFilePath).UpdateExceptionData(e) : e;
public override void Throw(CommonExceptionType commonExceptionType, [Optional] IEnumerable<object> interpolationValues,
[CallerMemberName] in str callerName="", [CallerLineNumber]in int callerLineNumber=0, [CallerFilePath]in str callerFilePath="" )
throw Create(commonExceptionType, interpolationValues, callerName, callerLineNumber, callerFilePath);
protected Exception updateExceptionInfo(Exception exception, in str callerName="", in int callerLineNumber=0, in str callerFilePath="")
var callerInfo=new CallerInfo(callerName, callerLineNumber, callerFilePath);
var arr=callerInfo.ToArray();
for(var c=0;c<arr.Length;c++) exception.Data[arr[c].Key]=arr[c].Value;
exception.Source=callerInfo.ToString();
public class TypeExceptionBuilder<TKey>(IDictionary<TKey, (Type TypeOfException, string Message)> typeToMessageXref, [Optional] bool includeExtendedInfo)
: BuilderBase<TKey, (Type TypeOfException, string Message)>(typeToMessageXref, includeExtendedInfo), IBuilder<TKey>
public override Exception Create(TKey typeOfException, [Optional] IEnumerable<object> interpolationValues,
[CallerMemberName] in str callerName="", [CallerLineNumber]in int callerLineNumber=0, [CallerFilePath]in str callerFilePath="" )
var message=Xrefs[typeOfException].Message;
var e=(Exception)Activator.CreateInstance(Xrefs[typeOfException].TypeOfException, [string.Format(string.Concat(message, string.Empty), interpolationValues)]);
return includeExtendedInfo ? new CallerInfo(callerName, callerLineNumber, callerFilePath).UpdateExceptionData(e) : e;
public override void Throw(TKey typeOfException, [Optional] IEnumerable<object> interpolationValues,
[CallerMemberName] in str callerName="", [CallerLineNumber]in int callerLineNumber=0, [CallerFilePath]in str callerFilePath="" )
=> throw Create(typeOfException, interpolationValues, callerName, callerLineNumber, callerFilePath);
public class FactoryExceptionBuilder<TKey>(IDictionary<TKey, (CustomExceptionFactoryDelegate Factory, string Message)> factoryToMessageXref, bool includeExtendedInfo=true)
: BuilderBase<TKey, (CustomExceptionFactoryDelegate Factory, string Message)>(
includeExtendedInfo), IBuilder<TKey>
private bool _isValidated;
public override Exception Create(TKey key, [Optional] IEnumerable<object> interpolationValues,
[CallerMemberName] in str callerName="", [CallerLineNumber]in int callerLineNumber=0, [CallerFilePath]in str callerFilePath="" )
if(!_isValidated) validateFactories();
var result=Xrefs[key].Factory.Invoke();
public override void Throw(TKey key, [Optional] IEnumerable<object> interpolationValues,
[CallerMemberName] in str callerName="", [CallerLineNumber]in int callerLineNumber=0, [CallerFilePath]in str callerFilePath="" )
=> throw Create(key, interpolationValues, callerName, callerLineNumber, callerFilePath);
private void validateFactories()
var valid=Xrefs.All(f=>f.Value.Factory() is Exception);
if(!valid) CommonException.Throw(CommonExceptionType.Argument, "A FactoryExceptionBuilder's factory must return an Exception type.");
for(var c=0;c<Xrefs.Count;c++)
var factory=Xrefs[c].Factory;
if(factory.Invoke() is not Exception)
CommonException.Throw(CommonExceptionType.Argument, "A FactoryExceptionBuilder's factory must return an Exception type.");
public class ExceptionBuilderManager(params IBuilder<dynamic> [] builders) : List<IBuilder<dynamic>>(builders)
public Exception Create<TKey>(TKey key, [Optional] IEnumerable<object> objects,
[CallerMemberName] in str callerName="", [CallerLineNumber]in int callerLineNumber=0, [CallerFilePath]in str callerFilePath="" )
var matches=this.Where(i=>i.HasKey(key));
if(!Enumerable.TryGetNonEnumeratedCount(matches, out int matchCount)) matchCount=matches.Count();
for(var b=0;b<matchCount;b++)
var builder=matches.ElementAt(b);
e=builder.Create(key, objects, callerName, callerLineNumber, callerFilePath);
if(e is not Exception) continue;
public void Throw<TKey>(TKey key, [Optional] IEnumerable<object> objects,
[CallerMemberName] in str callerName="", [CallerLineNumber]in int callerLineNumber=0, [CallerFilePath]in str callerFilePath="" )
=> throw Create<TKey>(key, objects, callerName, callerLineNumber, callerFilePath);
public class ExceptionBuilder2<TMessageKey>(IDictionary<TMessageKey, ExceptionInfo> exceptionInfos=null, bool includeExtendedInfo=true)
: CommonExceptionBuilder(includeExtendedInfo:includeExtendedInfo)
where TMessageKey : notnull
private protected const string KEYNOTFOUND="TMessageEnumKey value not found in ExceptionBuilder<TMessageEnumKey>";
protected MessageBuilder<TMessageKey> _messageBuilder=new MessageBuilder<TMessageKey>( exceptionInfos.ToDictionary(e=>e.Key, e=>e.Value.message) );
private IDictionary<TMessageKey, ExceptionInfo> _exceptionInfos=exceptionInfos;
public Exception Create(TMessageKey messageKey, CommonExceptionType exceptionType, [Optional] IEnumerable<object> interpolationValues,
[CallerMemberName] in str callerName="", [CallerLineNumber]in int callerLineNumber=0, [CallerFilePath]in str callerFilePath="" )
public Exception Create(TMessageKey messageKey, IEnumerable<object> interpolationValues,
[CallerMemberName] in str callerName="", [CallerLineNumber]in int callerLineNumber=0, [CallerFilePath]in str callerFilePath="")
if(!_exceptionInfos.ContainsKey(messageKey)) throw new ArgumentException(string.Concat(KEYNOTFOUND, ".Create(TMessageKey, IEnumerable<object>"));
var info=_exceptionInfos[messageKey];
if(info.factory is not null) return updateExceptionInfo(info.factory?.Invoke(info.message), callerName, callerLineNumber, callerFilePath);
public Exception Create(TMessageKey messageKey, Type? typeOfException, [Optional] IEnumerable<object> interpolationValues,
[CallerMemberName] in str callerName="", [CallerLineNumber]in int callerLineNumber=0, [CallerFilePath]in str callerFilePath="" )
if(!_exceptionInfos.ContainsKey(messageKey)) throw new ArgumentException(string.Concat(KEYNOTFOUND, ".Create(TMessageKey, IEnumerable<object>"));
var info=_exceptionInfos[messageKey];
if(info.factory is not null) return updateExceptionInfo(info.factory?.Invoke(info.message), callerName, callerLineNumber, callerFilePath);
public void Throw(TMessageKey messageKey, CommonExceptionType exceptionType, [Optional] IEnumerable<object> interpolationValues,
[CallerMemberName] in str callerName="", [CallerLineNumber]in int callerLineNumber=0, [CallerFilePath]in str callerFilePath="" )
=> throw Create(messageKey, exceptionType, interpolationValues, callerName, callerLineNumber, callerFilePath);
public void Throw(TMessageKey messageKey, [Optional] IEnumerable<object> interpolationValues,
[CallerMemberName] in str callerName="", [CallerLineNumber]in int callerLineNumber=0, [CallerFilePath]in str callerFilePath="" )
=> throw Create(messageKey, interpolationValues, callerName, callerLineNumber, callerFilePath);
public void Throw(TMessageKey messageKey, Type typeOfException, [Optional] IEnumerable<object> interpolationValues,
[CallerMemberName] in str callerName="", [CallerLineNumber]in int callerLineNumber=0, [CallerFilePath]in str callerFilePath="" )
=> throw Create(messageKey, typeOfException, interpolationValues, callerName, callerLineNumber, callerFilePath);
public class ExceptionBuilder<TMessageKey>(MessageBuilder<TMessageKey> messageBuilder, bool includeExtendedInfo=true)
: CommonExceptionBuilder(includeExtendedInfo:includeExtendedInfo)
where TMessageKey : notnull
protected MessageBuilder<TMessageKey> _messageBuilder=messageBuilder;
protected ImmutableDictionary<TMessageKey, CommonExceptionType> _messageXrefCommonExceptionType;
protected ImmutableDictionary<TMessageKey, Type> _messageXrefTypeOfException;
private bool _hasXref, _hasCustomXref;
public ExceptionBuilder(MessageBuilder<TMessageKey> messageBuilder,
[AllowNull] IDictionary<TMessageKey, CommonExceptionType> messageXrefCommonExceptionType,
[AllowNull] IDictionary<TMessageKey, Type> messageXrefTypeOfException)
addExceptionTypes(messageXrefCommonExceptionType);
addCustomExceptions(messageXrefTypeOfException);
public ExceptionBuilder(MessageBuilder<TMessageKey> messageBuilder, IDictionary<TMessageKey, CommonExceptionType> messageXrefCommonExceptionType)
: this(messageBuilder, messageXrefCommonExceptionType, null){}
public ExceptionBuilder(MessageBuilder<TMessageKey> messageBuilder, IDictionary<TMessageKey, Type> messageXrefTypeOfException)
: this(messageBuilder, null, messageXrefTypeOfException ){}
public Exception Create(CommonExceptionType exceptionType, TMessageKey messageKey, [Optional] IEnumerable<object> interpolationValues,
[CallerMemberName] in str callerName="", [CallerLineNumber]in int callerLineNumber=0, [CallerFilePath]in str callerFilePath="" )
public Exception Create(TMessageKey messageKey, [Optional] IEnumerable<object> interpolationValues,
[CallerMemberName] in str callerName="", [CallerLineNumber]in int callerLineNumber=0, [CallerFilePath]in str callerFilePath="" )
Exception result=new ArgumentException("Unable to create your exception.");
if(_hasCustomXref && _messageXrefTypeOfException.ContainsKey(messageKey))
result=Create( _hasXref && _messageXrefCommonExceptionType.ContainsKey(messageKey) ? _messageXrefCommonExceptionType[messageKey] : CommonExceptionType.Unknown, messageKey, interpolationValues, callerName, callerLineNumber, callerFilePath);
public void Throw(CommonExceptionType exceptionType, TMessageKey messageKey, [Optional] IEnumerable<object> interpolatedValues,
[CallerMemberName] in str callerName="", [CallerLineNumber]in int callerLineNumber=0, [CallerFilePath]in str callerFilePath="" )
=> throw Create(exceptionType, messageKey, interpolatedValues, callerName, callerLineNumber, callerFilePath);
public void Throw(TMessageKey messageKey, [Optional] IEnumerable<object> interpolationValues,
[CallerMemberName] in str callerName="", [CallerLineNumber]in int callerLineNumber=0, [CallerFilePath]in str callerFilePath="" )
=> throw Create(messageKey, interpolationValues, callerName, callerLineNumber, callerFilePath);
private void addExceptionTypes([AllowNull] IDictionary<TMessageKey, CommonExceptionType> messageXrefCommonExceptionType)
=> (_messageXrefCommonExceptionType, _hasXref)=(messageXrefCommonExceptionType?.ToImmutableDictionary(), messageXrefCommonExceptionType is not null && messageXrefCommonExceptionType.Count()>0);
private void addCustomExceptions([AllowNull] IDictionary<TMessageKey, Type> messageXrefTypeOfException)
=> (_messageXrefTypeOfException, _hasCustomXref)=(messageXrefTypeOfException?.ToImmutableDictionary(), messageXrefTypeOfException is not null && messageXrefTypeOfException.Count()>0 );
public class UtilityMethods
public static bool Try(Action action)
public static bool TryCatch(Action action, out Exception exception)
catch (Exception e) { exception=ExceptionDispatchInfo.Capture(e).SourceException; }
namespace ExtensionMethods
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
public static class ReflectionExtensionMethods
public static object?[] CreateConstructorParametersDefaultValues(this Type type, [Optional] Func<Type, object> abstractTypeCreationFactory, int constructorIndex=0)
var ctors=type.GetConstructors();
if(ctors is null) return Array.Empty<object>();
ParameterInfo [] ctorParameters=Array.Empty<ParameterInfo>();
if(ctors!=Array.Empty<ConstructorInfo>())
if(ctors.Length>=constructorIndex) ctor=ctors[constructorIndex]; else throw new ArgumentException("ConstructorIndex is out of range");
ctorParameters=ctor.GetParameters();
return ctorParameters.Length==0 ? Array.Empty<object>() : CreateParametersDefaultValues(parameters:ctorParameters, abstractTypeCreationFactory);
public static object?[] CreateMethodParametersDefaultValues([DN] this MethodInfo method, [Optional] Func<Type, object> abstractTypeCreationFactory)
var parameters=method.GetParameters();
if(!Enumerable.TryGetNonEnumeratedCount(parameters, out int count)) count=parameters.Count();
return parameters is null || count==0 ? Array.Empty<object>() : CreateParametersDefaultValues(parameters:parameters, abstractTypeCreationFactory);
public static object?[] CreateParametersDefaultValues(this ParameterInfo [] parameters, [Optional] Func<Type, object> abstractTypeCreationFactory)
if(parameters is null || parameters.Length==0) return Array.Empty<object>();
var returned=new object?[parameters.Length];
for(var c=0;c<parameters.Length;c++)
Type parameterType=parameters[c].ParameterType;
if (parameterType.IsAbstract && abstractTypeCreationFactory is not null)
returned[c]=abstractTypeCreationFactory?.Invoke(parameterType);
else if (!parameterType.IsAbstract)
returned[c]=System.Activator.CreateInstance(parameterType, parameterType.CreateConstructorParametersDefaultValues());
public static object? CreateType2<TInterface>(this Type implementationType, [Optional] Func<Type, object> abstractTypeCreationFactory, [Optional, DPV(0)] int constructorIndex, [Optional] params object [] parameterValues)
=> CreateType2(typeof(TInterface), implementationType, abstractTypeCreationFactory, constructorIndex, parameterValues);
public static object? CreateType2(this Type @interface, Type implementationType, [Optional] Func<Type, object> abstractTypeCreationFactory, [Optional, DPV(0)] int constructorIndex, [Optional] params object [] parameterValues)
if(!@interface.IsAbstract) throw new ArgumentException($"Parameter @interface ({@interface}) is not an abstract type.");
return CreateType2(implementationType, abstractTypeCreationFactory, constructorIndex, parameterValues);
public static object? CreateType2(this Type implementationType, [Optional] Func<Type, object> abstractTypeCreationFactory, [Optional, DPV(0)] int constructorIndex, [Optional] params object [] parameterValues)
object? returned=default;
if(parameterValues is null || parameterValues.Length==0)
returned=System.Activator.CreateInstance(implementationType, CreateConstructorParametersDefaultValues(implementationType, abstractTypeCreationFactory, constructorIndex));
else returned=System.Activator.CreateInstance(implementationType, parameterValues);
public static bool HasGenericInterface(this Type type, Type interf, Type typeparameter)
var result=type.GetInterfaces()
i=>i.IsGenericType && i.GetGenericTypeDefinition()==interf
i=>i.GetGenericArguments()[0]==typeparameter
foreach (Type i in type.GetInterfaces())
if (i.IsGenericType && i.GetGenericTypeDefinition() == interf)
if (i.GetGenericArguments()[0] == typeparameter)
public static bool HasGenericInterface(this Type type, Type interf, Type typeparameter, out Type foundInterface)
foundInterface=type.GetInterfaces()
i=>i.IsGenericType && i.GetGenericTypeDefinition()==interf
i=>i.GetGenericArguments()[0]==typeparameter
return Object.Equals(foundInterface,null);
public static bool HasInterface(this Type type, Type @interface) => type.GetInterfaces().Contains(@interface);
public static bool HasInterface(this object @object, Type @interface) => @object.GetType().GetInterfaces().Contains(@interface);
public static bool HasInterface<T>(Type @interface)
=> typeof(T).GetInterfaces().Contains(@interface);
public static bool TryGetType(string typeName, out Type target)
target=Type.GetType(typeName, false, true) ?? Type.Missing.GetType();
return target is not null;
public static int GetHashCodeSkeet(this object [] objs)
for(var c=0;c<objs.Length;c++)
hash = hash * 23 + objs[1].GetHashCode();
public static class Conditional
public static void If(this bool condition, Action action)
{ if(condition) action(); }
public static class AsyncMethods
public static Task<T> RunAsync<T>(this Func<T> f) => Task<T>.Factory.StartNew(f);
public static TaskAwaiter<T> GetAwaiter<T>(this T o)
var tcs=new TaskCompletionSource<T>();
return tcs.Task.GetAwaiter();
public static class ExceptionMethods
public static Exception AddData(this Exception e, params (string key, string value) [] kvp)
{ for(var c=0;c<kvp.Length;c++) e.Data[kvp[c].key]=kvp[c].value; return e; }
public static void ThrowIf(this Exception ex, Func<bool> validate, str message)
{ if(!validate()) throw new Exception(message); }
public static class StringMethods
public static string Append([DN]this StringBuilder sb, params string [] strings)
{ StringMethods.Append(sb, strings.AsSpan()); return sb.ToString(); }
public static string Append([DN]this StringBuilder sb, Span<string> strings)
{ EnumerableMethods.For(strings,s=>sb.Append(s)); return sb.ToString(); }
public static class CollectionMethods
private static SpinLock _lock;
public static TValue AddOrUpdate<TKey, TValue>(this Dictionary<TKey, TValue> data, in TKey key, Func<TKey, TValue> addFactory, Func<TKey,TValue,TValue> updateFactory, bool isThreadSafe=false)
if(!isThreadSafe) return doWork(ref data, key);
try { _lock.Enter(ref lockTaken); return doWork(ref data, key); }
finally { if (lockTaken) _lock.Exit(); }
TValue doWork(ref Dictionary<TKey, TValue> data, in TKey key)
ref var newOrOld=ref CollectionsMarshal.GetValueRefOrAddDefault<TKey, TValue>(data, key, out bool exists);
if(exists) newOrOld=updateFactory(key, newOrOld!); else newOrOld=addFactory(key);
public static TValue AddOrUpdate<TKey, TValue>(this Dictionary<TKey, TValue> data, in TKey key, TValue value, bool isThreadSafe=false)
=> CollectionMethods.AddOrUpdate<TKey, TValue>(data, key, key=>value, (key, old)=>value);
public static TValue AddOrUpdate<TKey, TValue>(this ConcurrentDictionary<TKey, TValue> data, in TKey key, Func<TKey, TValue> addFactory, Func<TKey,TValue,TValue> updateFactory, bool isThreadSafe=false)
=>CollectionMethods.AddOrUpdate(data, key, addFactory, updateFactory, isThreadSafe);
public static TValue AddOrUpdate<TKey, TValue>(this ConcurrentDictionary<TKey, TValue> data, in TKey key, TValue value)
=> CollectionMethods.AddOrUpdate(data:data, key:key, addFactory:(key)=>value, updateFactory:(key, old)=>value);
public static TValue AddOrUpdate<TKey, TValue>(this IDictionary<TKey, TValue> [] data, TKey key, Func<TKey, TValue> addFactory, Func<TKey,TValue,TValue> updateFactory, bool isThreadSafe=false )
=> CollectionMethods.AddOrUpdate(data, key, addFactory, updateFactory, isThreadSafe);
public static TValue AddOrUpdate<TKey, TValue>(this KeyValuePair<TKey, TValue> [] data, TKey key, Func<TKey, TValue> addFactory, Func<TKey,TValue,TValue> updateFactory, bool isThreadSafe=false )
if(!isThreadSafe) return doWork(ref data, key);
try { _lock.Enter(ref lockTaken); return doWork(ref data, key); }
finally { if (lockTaken) _lock.Exit(); }
TValue doWork(ref KeyValuePair<TKey, TValue> [] data, TKey key)
var item=data.First(pair=>pair.Key.Equals(key));
var result=default(TValue);
if(!Unsafe.IsNullRef(ref item))
item=KeyValuePair.Create(key, result);
result=updateFactory(key,item.Value);
data.Append(KeyValuePair.Create(key, result));
public static TValue AddOrUpdate<TKey, TValue>(this KeyValuePair<TKey, TValue> [] data, TKey key, TValue value, bool isThreadSafe=false)
=> CollectionMethods.AddOrUpdate(data, key, key=>value, (key, old)=>value, isThreadSafe);
public static class Conversion
public static T ChangeType<T>(this object val)
=> (T)Convert.ChangeType(val,typeof(T));
public static async IAsyncEnumerable<T> AsAsyncEnumerable<T>(this IEnumerable<T> input)
{ foreach(var value in input) { yield return value; } }
public static IEnumerable<T> ToEnumerable<T>(this IAsyncEnumerable<T> asyncEnumerable)
=> (IEnumerable<T>)asyncEnumerable.ToBlockingEnumerable();
public static class EnumerableMethods
public static bool IsEmpty<T>([DN] this IEnumerable<T> e)
if(!e.TryGetNonEnumeratedCount(out int count)) count=e.Count();
public static void For<T>([DN]this Span<T> span, Action<T> action)
=> EnumerableMethods.For(span, 0, span.Length, action);
public static void For<T>([DN]this ReadOnlySpan<T> span, Action<T> action)
=> EnumerableMethods.For(span, 0, span.Length, action);
public static void For<T>([DN]this IEnumerable<T> e, Action<T> action)
if(!e.TryGetNonEnumeratedCount(out int count)) count=e.Count();
EnumerableMethods.For<T>( e.ToArray().ToReadOnlySpan(), 0, count, action);
public static ReadOnlySpan<TResult> For<T,TResult>([DN]this Span<T> span, Func<T,TResult> function)
=> EnumerableMethods.For(span, 0, span.Length, function);
public static ReadOnlySpan<TResult> For<T,TResult>([DN]this ReadOnlySpan<T> span, Func<T,TResult> function)
=> EnumerableMethods.For(span, 0, span.Length, function);
public static ReadOnlySpan<TResult> For<T, TResult>([DN]this IEnumerable<T> list, Func<T,TResult> function)
if(!list.TryGetNonEnumeratedCount(out int count)) count=list.Count();
return EnumerableMethods.For(list.ToReadOnlySpan(), 0, count, function);
public static void For<T>([DN]this ReadOnlySpan<T> source, int minInclusive, int maxExclusive, Action<T> action)
if(source.IsEmpty) return;
ref var searchSpace=ref MemoryMarshal.GetReference(source);
for(var c=minInclusive;c<maxExclusive;c++)
var item=Unsafe.Add(ref searchSpace, c);
public static ReadOnlySpan<TResult> For<T, TResult>([DN]this ReadOnlySpan<T> source, int minInclusive, int maxExclusive, Func<T, TResult> function)
if(source.IsEmpty) return ReadOnlySpan<TResult>.Empty;
ref var searchSpace=ref MemoryMarshal.GetReference(source);
var results=new TResult [source.Length];
for(var c=minInclusive;c<maxExclusive;c++)
var item=Unsafe.Add(ref searchSpace, c);
results[c]=function(item);
return new ReadOnlySpan<TResult>(results);
public static class ValidationMethods
public static void Validate<T>(this T item, [DN]bool condition=true, str friendlyMessage=null, str friendlyParameterName=null, [CallerArgumentExpression("condition")] string? argumentMessage=null)
if (!condition) throw new ArgumentException(
string.Concat($"Argument failed validation: <{argumentMessage}>",
friendlyMessage is null ? string.Empty : $"\t{friendlyMessage}"),
friendlyParameterName is null ? string.Empty : friendlyParameterName);
public static class SpanMemoryMethods
public static Span<T> ToSpan<T>([DN]this T to) => new Span<T>([to]);
public static Memory<T> ToMemory<T>([DN]this T to) => new Memory<T>([to]);
public static ReadOnlySpan<T> ToReadOnlySpan<T>([DN]this T to) =>new ReadOnlySpan<T>([to]);
public static ReadOnlySpan<T> ToReadOnlySpan<T>([DN]this T [] to) =>new ReadOnlySpan<T>(to);
public static ReadOnlySpan<T> ToReadOnlySpan<T>([DN]this Span<T> span)
=> span.IsEmpty ? ReadOnlySpan<T>.Empty : (ReadOnlySpan<T>)span;
public static ReadOnlySpan<T> ToReadOnlySpan<T>([DN]this IEnumerable<T> e)
if(!e.TryGetNonEnumeratedCount(out int count)) count=e.Count();
return count==0 ? ReadOnlySpan<T>.Empty : (ReadOnlySpan<T>)e.ToArray();
public static ReadOnlyMemory<T> ToReadOnlyMemory<T>([DN]this T to)=>new ReadOnlyMemory<T>([to]);
public static ReadOnlyMemory<T> ToReadOnlyMemory<T>([DN]this Span<T> span)
=> span.IsEmpty ? ReadOnlyMemory<T>.Empty : new ReadOnlyMemory<T>(span.ToArray());
public static ReadOnlyMemory<T> ToReadOnlyMemory<T>([DN]this IEnumerable<T> e)
if(!e.TryGetNonEnumeratedCount(out int count)) count=e.Count();
return count==0 ? ReadOnlyMemory<T>.Empty : (ReadOnlyMemory<T>)e.ToArray();
public static ReadOnlySpan<TResult> Parse<T, TResult>([DN] this IEnumerable<T> fromThis, [DN]Func<T,TResult> function)
if(!fromThis.TryGetNonEnumeratedCount(out int count)) count=fromThis.Count();
return count==0 ? ReadOnlySpan<TResult>.Empty : fromThis.For(item=>function(item));
public static TResult Parse<T, TResult>([DN] this T fromThis, [DN]Func<T,TResult> function)=> function(fromThis);
public static class Validation
public static void ValidateArgument([DN]string parameterName, [DN]bool validateState=true, str friendlyMessage=null, [CallerArgumentExpression("validateState")] string argumentMessage="")
if (!validateState) throw new ArgumentException(
string.Concat($"Argument failed validation: <{argumentMessage}>", friendlyMessage is null ? string.Empty : $"\t{friendlyMessage}"), parameterName);
public static void ValidateArgument(string parameterName, [DN] IEnumerable<bool> validateStates, str friendlyMessage=null)
ValidateArgument("IEnumerable<bool>", validateStates is not null, "Enumerable must not be null.");
if(!validateStates.TryGetNonEnumeratedCount(out int validateStatesCount)) validateStatesCount=validateStates.Count();
ValidateArgument("IEnumerable<bool>", validateStatesCount>0, "Enumerable must not be empty.");
var conditionsSpan=CollectionsMarshal.AsSpan<bool>(validateStates.ToList());
ref var searchSpace=ref MemoryMarshal.GetReference(conditionsSpan);
for(var i=0;i<conditionsSpan.Length;i++)
var condition=Unsafe.Add(ref searchSpace,i);
ValidateArgument(parameterName, condition, friendlyMessage);
public static void ValidateArgument(string parameterName, [DN] IEnumerable<bool> validateStates, [Optional] IEnumerable<str> friendlyMessages)
ValidateArgument("IEnumerable<bool>", validateStates is not null, "Enumerables must not be null.");
if(!validateStates.TryGetNonEnumeratedCount(out int validateStatesCount)) validateStatesCount=validateStates.Count();
if(!friendlyMessages.TryGetNonEnumeratedCount(out int friendlyMessagesCount)) friendlyMessagesCount=friendlyMessages.Count();
ValidateArgument("IEnumerable<bool>", validateStatesCount>0, "Enumerables must not be empty.");
if(friendlyMessagesCount>0)
ValidateArgument("IEnumerable<bool> and IEnumerable<str>", validateStatesCount==friendlyMessagesCount, "Enumerables must have the same count.");
var conditionsSpan=CollectionsMarshal.AsSpan<bool>(validateStates.ToList());
var messagesSpan=CollectionsMarshal.AsSpan<str>(friendlyMessages.ToList());
ref var conditionsSpace=ref MemoryMarshal.GetReference(conditionsSpan);
ref var messagesSpace=ref MemoryMarshal.GetReference(messagesSpan);
for(var i=0;i<conditionsSpan.Length;i++)
var condition=Unsafe.Add(ref conditionsSpace,i);
var message=Unsafe.Add(ref messagesSpace,i);
ValidateArgument(parameterName, condition, message);
public static void ValidateArguments([DN] IEnumerable<string> parameterNames,[DN] IEnumerable<bool> validateStates, [Optional] IEnumerable<str> friendlyMessages)
ValidateArgument("IEnumerable<bool> and IEnumerable<str>", parameterNames is not null && validateStates is not null && friendlyMessages is not null, "Enumerables must not be null.");
if(!parameterNames.TryGetNonEnumeratedCount(out int parameterNamesCount)) parameterNamesCount=parameterNames.Count();
if(!validateStates.TryGetNonEnumeratedCount(out int validateStatesCount)) validateStatesCount=validateStates.Count();
if(!friendlyMessages.TryGetNonEnumeratedCount(out int friendlyMessagesCount)) friendlyMessagesCount=friendlyMessages.Count();
ValidateArgument("IEnumerable<bool> and IEnumerable<str>", parameterNamesCount>0 && validateStatesCount>0 && friendlyMessagesCount>0, "Enumerables must not be empty.");
ValidateArgument("IEnumerable<bool> and IEnumerable<str>", parameterNamesCount==validateStatesCount && parameterNamesCount==friendlyMessagesCount, "Enumerables must have the same count.");
if(friendlyMessagesCount>0)
ValidateArgument("IEnumerable<bool> and IEnumerable<str>", validateStatesCount==friendlyMessagesCount, "Enumerables must have the same count.");
var parametersSpan=CollectionsMarshal.AsSpan<str>(parameterNames.ToList());
var conditionsSpan=CollectionsMarshal.AsSpan<bool>(validateStates.ToList());
var messagesSpan=CollectionsMarshal.AsSpan<str>(friendlyMessages.ToList());
ref var parametersSpace=ref MemoryMarshal.GetReference(parametersSpan);
ref var conditionsSpace=ref MemoryMarshal.GetReference(conditionsSpan);
ref var messagesSpace=ref MemoryMarshal.GetReference(messagesSpan);
for(var i=0;i<conditionsSpan.Length;i++)
var parameter=Unsafe.Add(ref parametersSpace,i);
var condition=Unsafe.Add(ref conditionsSpace,i);
var message=Unsafe.Add(ref messagesSpace,i);
ValidateArgument(parameter, condition, message);
public static void ValidateArgument(string parameterName, Func<bool> validateState, str friendlyMessage=null, [CallerArgumentExpression("validateState")] string? argumentMessage=null)
if(validateState is null) return;
if (!validateState()) throw new ArgumentException(
string.Concat($"Argument failed validation: <{argumentMessage}>", friendlyMessage is null ? string.Empty : $"\t{friendlyMessage}"), parameterName);
public static void ValidateArgument(string parameterName,[DN] IEnumerable<Func<bool>> validateStates, [Optional] str friendlyMessage)
ValidateArgument("IEnumerable<Func<bool>>", validateStates is not null, "Enumerables must not be null.");
if(!validateStates.TryGetNonEnumeratedCount(out int validateStatesCount)) validateStatesCount=validateStates.Count();
ValidateArgument("IEnumerable<Func<bool>>", validateStatesCount>0, "Enumerables must not be empty.");
var conditionsSpan=CollectionsMarshal.AsSpan<Func<bool>>(validateStates.ToList());
ref var searchSpace=ref MemoryMarshal.GetReference(conditionsSpan);
for(var i=0;i<conditionsSpan.Length;i++)
var condition=Unsafe.Add(ref searchSpace,i);
if(condition is null) continue;
ValidateArgument(parameterName, condition, friendlyMessage);
public static void ValidateArgument(string parameterName, [DN] IEnumerable<Func<bool>> validateStates, [Optional] IEnumerable<str> friendlyMessages)
ValidateArgument("IEnumerable<bool>", validateStates is not null, "Enumerables must not be null.");
if(!validateStates.TryGetNonEnumeratedCount(out int validateStatesCount)) validateStatesCount=validateStates.Count();
if(!friendlyMessages.TryGetNonEnumeratedCount(out int friendlyMessagesCount)) friendlyMessagesCount=friendlyMessages.Count();
ValidateArgument("IEnumerable<bool>", validateStatesCount>0, "Enumerables must not be empty.");
if(friendlyMessagesCount>0)
ValidateArgument("IEnumerable<bool> and IEnumerable<str>", validateStatesCount==friendlyMessagesCount, "Enumerables must have the same count.");
var conditionsSpan=CollectionsMarshal.AsSpan<Func<bool>>(validateStates.ToList());
var messagesSpan=CollectionsMarshal.AsSpan<str>(friendlyMessages.ToList());
ref var conditionsSpace=ref MemoryMarshal.GetReference(conditionsSpan);
ref var messagesSpace=ref MemoryMarshal.GetReference(messagesSpan);
for(var i=0;i<conditionsSpan.Length;i++)
var condition=Unsafe.Add(ref conditionsSpace,i);
if(condition is null) continue;
var message=Unsafe.Add(ref messagesSpace,i);
ValidateArgument(parameterName, condition, message);
public static void ValidateArguments([DN] IEnumerable<string> parameterNames, [DN] IEnumerable<Func<bool>> validateStates, [Optional] IEnumerable<str> friendlyMessages)
ValidateArgument("IEnumerable<bool> and IEnumerable<str>", parameterNames is not null && validateStates is not null && friendlyMessages is not null, "Enumerables must not be null.");
if(!parameterNames.TryGetNonEnumeratedCount(out int parameterNamesCount)) parameterNamesCount=parameterNames.Count();
if(!validateStates.TryGetNonEnumeratedCount(out int validateStatesCount)) validateStatesCount=validateStates.Count();
if(!friendlyMessages.TryGetNonEnumeratedCount(out int friendlyMessagesCount)) friendlyMessagesCount=friendlyMessages.Count();
ValidateArgument("IEnumerable<bool> and IEnumerable<str>", parameterNamesCount>0 && validateStatesCount>0, "Enumerables must not be empty.");
if(friendlyMessagesCount>0)
ValidateArgument("IEnumerable<bool> and IEnumerable<str>", validateStatesCount==friendlyMessagesCount, "Enumerables must have the same count.");
var parametersSpan=CollectionsMarshal.AsSpan<str>(parameterNames.ToList());
var conditionsSpan=CollectionsMarshal.AsSpan<Func<bool>>(validateStates.ToList());
var messagesSpan=CollectionsMarshal.AsSpan<str>(friendlyMessages.ToList());
ref var parametersSpace=ref MemoryMarshal.GetReference(parametersSpan);
ref var conditionsSpace=ref MemoryMarshal.GetReference(conditionsSpan);
ref var messagesSpace=ref MemoryMarshal.GetReference(messagesSpan);
for(var i=0;i<conditionsSpan.Length;i++)
var condition=Unsafe.Add(ref conditionsSpace,i);
if(condition is null) continue;
var parameter=Unsafe.Add(ref parametersSpace,i);
var message=Unsafe.Add(ref messagesSpace,i);
ValidateArgument(parameter, condition, message);
public static class DebugMethods
public static int DebugCallCount=0;
public static bool debug=true;
public static void DoNothing() {}
public static void L() { if(debug) { Console.Write("\n");} }
public static void W<T>(T s) { if(debug) { Console.Write(s);} }
public static void WL<T>(T s) { if(debug) { Console.WriteLine(s);} }
public static void Hi(object message=null, [System.Runtime.CompilerServices.CallerMemberName] in str callerName="", [System.Runtime.CompilerServices.CallerLineNumber]in int callerLineNumber=0, [CallerFilePath]in str callerFilePath="")
Console.Write($"HI {DebugCallCount}>\t(Name: {callerName}\tLineNumber: {callerLineNumber}");
if(callerFilePath is not null && !string.IsNullOrWhiteSpace(callerFilePath + "")) Console.Write($"\tFile: {callerFilePath}");
if(message is not null && !string.IsNullOrWhiteSpace(message+"")) Console.Write($"\n\t\t\t--- {message}");
public static void Hi([DN]object [] messages, [System.Runtime.CompilerServices.CallerMemberName] in str callerName="", [System.Runtime.CompilerServices.CallerLineNumber]in int callerLineNumber=0, [CallerFilePath]in str callerFilePath="")
Console.Write($"HI {DebugCallCount}>\t(Name: {callerName}\tLineNumber: {callerLineNumber}");
if(callerFilePath is not null && !string.IsNullOrWhiteSpace(callerFilePath + "")) Console.Write($"\tFile: {callerFilePath}");
foreach(var message in messages)
if(message is not null && !string.IsNullOrWhiteSpace(message+"")) Console.Write($"\n\t\t\t--- {message}");