add agresive injections

This commit is contained in:
Mikhail 2024-05-13 18:11:44 +08:00
parent 64dcda0157
commit b7ab56b645
3 changed files with 79 additions and 41 deletions

View File

@ -5,8 +5,8 @@ namespace DCFApixels.DragonECS
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method, Inherited = false, AllowMultiple = false)] [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
public sealed class EcsInjectAttribute : Attribute public sealed class EcsInjectAttribute : Attribute
{ {
public static readonly EcsInjectAttribute Dummy = new EcsInjectAttribute(null);
public readonly Type notNullDummyType; public readonly Type notNullDummyType;
public EcsInjectAttribute(Type notNullDummyType = null) public EcsInjectAttribute(Type notNullDummyType = null)
{ {
this.notNullDummyType = notNullDummyType; this.notNullDummyType = notNullDummyType;

View File

@ -9,102 +9,129 @@ namespace DCFApixels.DragonECS
internal class AutoInjectionMap internal class AutoInjectionMap
{ {
private readonly EcsPipeline _source; private readonly EcsPipeline _source;
private Dictionary<Type, List<InjectedPropertyRecord>> _systemProoperties; private Dictionary<Type, List<InjectedPropertyRecord>> _systemProperties;
private HashSet<Type> _notInjected; private HashSet<Type> _notInjected;
private bool _isDummyInjected = false; private bool _isDummyInjected = false;
private bool _isPreInitInjectionComplete = false; private bool _isPreInitInjectionComplete = false;
public AutoInjectionMap(EcsPipeline source) public AutoInjectionMap(EcsPipeline source, bool isAgressiveInjection = false)
{ {
_source = source; _source = source;
var allsystems = _source.AllSystems; var allsystems = _source.AllSystems;
_systemProoperties = new Dictionary<Type, List<InjectedPropertyRecord>>(); _systemProperties = new Dictionary<Type, List<InjectedPropertyRecord>>();
_notInjected = new HashSet<Type>(); _notInjected = new HashSet<Type>();
foreach (var system in allsystems) foreach (var system in allsystems)
{ {
Type systemType = system.GetType(); Type systemType = system.GetType();
foreach (var property in GetAllPropertiesFor(systemType)) if (systemType == typeof(AutoInjectSystem)) { continue; }
foreach (var property in GetAllPropertiesFor(systemType, isAgressiveInjection))
{ {
Type fieldType = property.PropertyType; Type propertType = property.PropertyType;
List<InjectedPropertyRecord> list; List<InjectedPropertyRecord> list;
if (!_systemProoperties.TryGetValue(fieldType, out list)) if (!_systemProperties.TryGetValue(propertType, out list))
{ {
list = new List<InjectedPropertyRecord>(); list = new List<InjectedPropertyRecord>();
_systemProoperties.Add(fieldType, list); _systemProperties.Add(propertType, list);
} }
list.Add(new InjectedPropertyRecord(system, property)); list.Add(new InjectedPropertyRecord(system, property));
} if (property.GetAutoInjectAttribute() != EcsInjectAttribute.Dummy)
}
foreach (var item in _systemProoperties.Keys)
{ {
_notInjected.Add(item); _notInjected.Add(propertType);
} }
} }
}
//foreach (var pair in _systemProperties)
//{
// _notInjected.Add(pair.Key);
//}
}
private static void Do(Type type, List<IInjectedProperty> result) //private bool IsInjectTarget(MemberInfo member)
//{
// return _isAgressiveInjection || member.GetCustomAttribute<EcsInjectAttribute>() != null;
//}
private static void Do(Type type, List<IInjectedProperty> result, bool isAgressiveInjection)
{ {
const BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; const BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
result.AddRange(type.GetFields(bindingFlags) result.AddRange(type.GetFields(bindingFlags)
.Where(o => o.GetCustomAttribute<EcsInjectAttribute>() != null) .Where(o => isAgressiveInjection || o.GetCustomAttribute<EcsInjectAttribute>() != null)
.Select(o => new InjectedField(o))); .Select(o => new InjectedField(o)));
result.AddRange(type.GetProperties(bindingFlags) result.AddRange(type.GetProperties(bindingFlags)
.Where(o => .Where(o =>
{ {
if (o.GetCustomAttribute<EcsInjectAttribute>() == null) if (!isAgressiveInjection && o.GetCustomAttribute<EcsInjectAttribute>() == null)
{
return false; return false;
}
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (o.CanWrite == false) Throw.PropertyIsCantWrite(o); if (!isAgressiveInjection && o.CanWrite == false) { Throw.PropertyIsCantWrite(o); }
#endif #endif
return true; return o.CanWrite == false;
}) })
.Select(o => new InjectedProperty(o))); .Select(o => new InjectedProperty(o)));
result.AddRange(type.GetMethods(bindingFlags) result.AddRange(type.GetMethods(bindingFlags)
.Where(o => .Where(o =>
{ {
if (o.GetCustomAttribute<EcsInjectAttribute>() == null) if (!isAgressiveInjection && o.GetCustomAttribute<EcsInjectAttribute>() == null)
{
return false; return false;
}
var parameters = o.GetParameters();
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (o.IsGenericMethod) Throw.MethodIsGeneric(o); if (!isAgressiveInjection)
if (o.GetParameters().Length != 1) Throw.MethodArgumentsGreater1(o); {
if (o.IsGenericMethod) { Throw.MethodIsGeneric(o); }
if (parameters.Length != 1) { Throw.MethodArgumentsGreater1(o); }
}
#endif #endif
return true; return o.IsGenericMethod == false && parameters.Length == 1;
}) })
.Select(o => new InjectedMethod(o))); .Select(o => new InjectedMethod(o)));
if (type.BaseType != null) if (type.BaseType != null)
Do(type.BaseType, result); {
Do(type.BaseType, result, isAgressiveInjection);
}
} }
private static List<IInjectedProperty> GetAllPropertiesFor(Type type) private static List<IInjectedProperty> GetAllPropertiesFor(Type type, bool isAgressiveInjection)
{ {
List<IInjectedProperty> result = new List<IInjectedProperty>(); List<IInjectedProperty> result = new List<IInjectedProperty>();
Do(type, result); Do(type, result, isAgressiveInjection);
return result; return result;
} }
public void Inject(Type fieldType, object obj) public void Inject(Type fieldType, object obj)
{ {
if (!_isPreInitInjectionComplete) if (!_isPreInitInjectionComplete)
{
_notInjected.Remove(fieldType); _notInjected.Remove(fieldType);
}
if (_systemProperties.TryGetValue(fieldType, out List<InjectedPropertyRecord> list))
{
foreach (var item in list)
{
item.property.Inject(item.target, obj);
}
}
Type baseType = fieldType.BaseType; Type baseType = fieldType.BaseType;
if (baseType != null) if (baseType != null)
Inject(baseType, obj);
if (_systemProoperties.TryGetValue(fieldType, out List<InjectedPropertyRecord> list))
{ {
foreach (var item in list) Inject(baseType, obj);
item.property.Inject(item.target, obj);
} }
} }
public void InjectDummy() public void InjectDummy()
{ {
if (_isDummyInjected) if (_isDummyInjected) { return; }
return;
_isDummyInjected = true; _isDummyInjected = true;
foreach (var notInjectedItem in _notInjected) foreach (var notInjectedItem in _notInjected)
{ {
foreach (var systemRecord in _systemProoperties[notInjectedItem]) foreach (var systemRecord in _systemProperties[notInjectedItem])
{ {
if (systemRecord.Attribute.notNullDummyType == null) if (systemRecord.Attribute.notNullDummyType == null)
continue; continue;
@ -128,9 +155,11 @@ namespace DCFApixels.DragonECS
#if DEBUG #if DEBUG
foreach (var item in _notInjected) foreach (var item in _notInjected)
{ {
foreach (var systemRecord in _systemProoperties[item]) foreach (var systemRecord in _systemProperties[item])
{
EcsDebug.PrintWarning($"in system {EcsDebugUtility.GetGenericTypeFullName(systemRecord.target.GetType(), 1)} is missing an injection of {EcsDebugUtility.GetGenericTypeFullName(item, 1)}."); EcsDebug.PrintWarning($"in system {EcsDebugUtility.GetGenericTypeFullName(systemRecord.target.GetType(), 1)} is missing an injection of {EcsDebugUtility.GetGenericTypeFullName(item, 1)}.");
} }
}
#endif #endif
} }
@ -143,7 +172,7 @@ namespace DCFApixels.DragonECS
{ {
public readonly IEcsProcess target; public readonly IEcsProcess target;
public readonly IInjectedProperty property; public readonly IInjectedProperty property;
public EcsInjectAttribute Attribute => property.GetAutoInjectAttribute(); public EcsInjectAttribute Attribute { get { return property.GetAutoInjectAttribute(); } }
public InjectedPropertyRecord(IEcsProcess target, IInjectedProperty property) public InjectedPropertyRecord(IEcsProcess target, IInjectedProperty property)
{ {
this.target = target; this.target = target;
@ -159,10 +188,16 @@ namespace DCFApixels.DragonECS
{ {
private EcsPipeline _pipeline; private EcsPipeline _pipeline;
EcsPipeline IEcsPipelineMember.Pipeline { get => _pipeline; set => _pipeline = value; } EcsPipeline IEcsPipelineMember.Pipeline { get => _pipeline; set => _pipeline = value; }
private List<object> _delayedInjects = new List<object>(); private List<object> _delayedInjects = new List<object>();
private AutoInjectionMap _autoInjectionMap; private AutoInjectionMap _autoInjectionMap;
private bool _isInitInjectionCompleted; private bool _isInitInjectionCompleted;
private bool _isAgressiveInjection;
public AutoInjectSystem(bool isAgressiveInjection = false)
{
_isAgressiveInjection = isAgressiveInjection;
}
public void Inject(object obj) public void Inject(object obj)
{ {
if (_isInitInjectionCompleted) if (_isInitInjectionCompleted)
@ -177,7 +212,7 @@ namespace DCFApixels.DragonECS
public void OnInitInjectionComplete() public void OnInitInjectionComplete()
{ {
_autoInjectionMap = new AutoInjectionMap(_pipeline); _autoInjectionMap = new AutoInjectionMap(_pipeline, _isAgressiveInjection);
_isInitInjectionCompleted = true; _isInitInjectionCompleted = true;
foreach (var obj in _delayedInjects) foreach (var obj in _delayedInjects)
@ -211,8 +246,9 @@ namespace DCFApixels.DragonECS
{ {
_member = member; _member = member;
_injectAttribute = member.GetCustomAttribute<EcsInjectAttribute>(); _injectAttribute = member.GetCustomAttribute<EcsInjectAttribute>();
if (_injectAttribute == null) { _injectAttribute = EcsInjectAttribute.Dummy; }
} }
public EcsInjectAttribute GetAutoInjectAttribute() => _injectAttribute; public EcsInjectAttribute GetAutoInjectAttribute() { return _injectAttribute; }
public void Inject(object target, object value) public void Inject(object target, object value)
{ {
_member.SetValue(target, value); _member.SetValue(target, value);
@ -229,8 +265,9 @@ namespace DCFApixels.DragonECS
{ {
_member = member; _member = member;
_injectAttribute = member.GetCustomAttribute<EcsInjectAttribute>(); _injectAttribute = member.GetCustomAttribute<EcsInjectAttribute>();
if (_injectAttribute == null) { _injectAttribute = EcsInjectAttribute.Dummy; }
} }
public EcsInjectAttribute GetAutoInjectAttribute() => _injectAttribute; public EcsInjectAttribute GetAutoInjectAttribute() { return _injectAttribute; }
public void Inject(object target, object value) public void Inject(object target, object value)
{ {
_member.SetValue(target, value); _member.SetValue(target, value);
@ -249,8 +286,9 @@ namespace DCFApixels.DragonECS
_member = member; _member = member;
_injectAttribute = member.GetCustomAttribute<EcsInjectAttribute>(); _injectAttribute = member.GetCustomAttribute<EcsInjectAttribute>();
propertyType = _member.GetParameters()[0].ParameterType; propertyType = _member.GetParameters()[0].ParameterType;
if (_injectAttribute == null) { _injectAttribute = EcsInjectAttribute.Dummy; }
} }
public EcsInjectAttribute GetAutoInjectAttribute() => _injectAttribute; public EcsInjectAttribute GetAutoInjectAttribute() { return _injectAttribute; }
public void Inject(object target, object value) public void Inject(object target, object value)
{ {
_member.Invoke(target, new object[] { value }); _member.Invoke(target, new object[] { value });

View File

@ -2,9 +2,9 @@
{ {
public static class AutoInjectSystemExtensions public static class AutoInjectSystemExtensions
{ {
public static EcsPipeline.Builder AutoInject(this EcsPipeline.Builder self) public static EcsPipeline.Builder AutoInject(this EcsPipeline.Builder self, bool isAgressiveInjection = false)
{ {
self.Add(new AutoInjectSystem()); self.Add(new AutoInjectSystem(isAgressiveInjection));
return self; return self;
} }
} }