mirror of
https://github.com/SK-la/osu-framework.git
synced 2026-03-15 03:20:30 +00:00
Combine source-gen and reflection BDL pathways
This commit is contained in:
@@ -11,6 +11,7 @@ using System.Runtime.ExceptionServices;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Extensions.TypeExtensions;
|
||||
using osu.Framework.Statistics;
|
||||
using osu.Framework.Utils;
|
||||
|
||||
namespace osu.Framework.Allocation
|
||||
{
|
||||
@@ -89,13 +90,7 @@ namespace osu.Framework.Allocation
|
||||
}
|
||||
}
|
||||
|
||||
private static Func<IReadOnlyDependencyContainer, object> getDependency(Type type, Type requestingType, bool permitNulls) => dc =>
|
||||
{
|
||||
object val = dc.Get(type);
|
||||
if (val == null && !permitNulls)
|
||||
throw new DependencyNotRegisteredException(requestingType, type);
|
||||
|
||||
return val;
|
||||
};
|
||||
private static Func<IReadOnlyDependencyContainer, object> getDependency(Type type, Type requestingType, bool permitNulls)
|
||||
=> dc => SourceGeneratorUtils.GetDependency(dc, type, requestingType, null, null, permitNulls, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ using JetBrains.Annotations;
|
||||
using osu.Framework.Extensions.TypeExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Statistics;
|
||||
using osu.Framework.Utils;
|
||||
|
||||
namespace osu.Framework.Allocation
|
||||
{
|
||||
@@ -127,23 +128,20 @@ namespace osu.Framework.Allocation
|
||||
|
||||
var additionActivators = new List<Action<object, DependencyContainer, CacheInfo>>();
|
||||
|
||||
// Types within the framework should be able to cache value types if they desire (e.g. cancellation tokens)
|
||||
bool allowValueTypes = type.Assembly == typeof(Drawable).Assembly;
|
||||
|
||||
foreach (var iface in type.GetInterfaces())
|
||||
{
|
||||
foreach (var attribute in iface.GetCustomAttributes<CachedAttribute>())
|
||||
additionActivators.Add((target, dc, info) => dc.CacheAs(attribute.Type ?? iface, new CacheInfo(info.Name ?? attribute.Name, info.Parent), target, allowValueTypes));
|
||||
additionActivators.Add((target, dc, info) => SourceGeneratorUtils.CacheDependency(dc, type, target, info, attribute.Type ?? iface, attribute.Name, null));
|
||||
}
|
||||
|
||||
foreach (var attribute in type.GetCustomAttributes<CachedAttribute>())
|
||||
additionActivators.Add((target, dc, info) => dc.CacheAs(attribute.Type ?? type, new CacheInfo(info.Name ?? attribute.Name, info.Parent), target, allowValueTypes));
|
||||
additionActivators.Add((target, dc, info) => SourceGeneratorUtils.CacheDependency(dc, type, target, info, attribute.Type ?? type, attribute.Name, null));
|
||||
|
||||
foreach (var property in type.GetProperties(ACTIVATOR_FLAGS).Where(f => f.GetCustomAttributes<CachedAttribute>().Any()))
|
||||
additionActivators.AddRange(createMemberActivator(property, type, allowValueTypes));
|
||||
additionActivators.AddRange(createMemberActivator(property, type));
|
||||
|
||||
foreach (var field in type.GetFields(ACTIVATOR_FLAGS).Where(f => f.GetCustomAttributes<CachedAttribute>().Any()))
|
||||
additionActivators.AddRange(createMemberActivator(field, type, allowValueTypes));
|
||||
additionActivators.AddRange(createMemberActivator(field, type));
|
||||
|
||||
if (additionActivators.Count == 0)
|
||||
return (_, existing, _) => existing;
|
||||
@@ -158,7 +156,7 @@ namespace osu.Framework.Allocation
|
||||
};
|
||||
}
|
||||
|
||||
private static IEnumerable<Action<object, DependencyContainer, CacheInfo>> createMemberActivator(MemberInfo member, Type type, bool allowValueTypes)
|
||||
private static IEnumerable<Action<object, DependencyContainer, CacheInfo>> createMemberActivator(MemberInfo member, Type type)
|
||||
{
|
||||
switch (member)
|
||||
{
|
||||
@@ -208,23 +206,7 @@ namespace osu.Framework.Allocation
|
||||
if (member is FieldInfo f)
|
||||
value = f.GetValue(target);
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
if (allowValueTypes)
|
||||
return;
|
||||
|
||||
throw new NullDependencyException($"Attempted to cache a null value: {type.ReadableName()}.{member.Name}.");
|
||||
}
|
||||
|
||||
var cacheInfo = new CacheInfo(info.Name ?? attribute.Name);
|
||||
|
||||
if (info.Parent != null)
|
||||
{
|
||||
// When a parent type exists, infer the property name if one is not provided
|
||||
cacheInfo = new CacheInfo(cacheInfo.Name ?? member.Name, info.Parent);
|
||||
}
|
||||
|
||||
dc.CacheAs(attribute.Type ?? value.GetType(), cacheInfo, value, allowValueTypes);
|
||||
SourceGeneratorUtils.CacheDependency(dc, type, value, info, attribute.Type, attribute.Name, member.Name);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,10 +9,10 @@ using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.TypeExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Statistics;
|
||||
using osu.Framework.Utils;
|
||||
|
||||
namespace osu.Framework.Allocation
|
||||
{
|
||||
@@ -114,17 +114,8 @@ namespace osu.Framework.Allocation
|
||||
};
|
||||
}
|
||||
|
||||
private static Func<IReadOnlyDependencyContainer, object> getDependency(Type type, Type requestingType, bool permitNulls, CacheInfo info) => dc =>
|
||||
{
|
||||
object val = dc.Get(type, info);
|
||||
if (val == null && !permitNulls)
|
||||
throw new DependencyNotRegisteredException(requestingType, type);
|
||||
|
||||
if (val is IBindable bindableVal)
|
||||
return bindableVal.GetBoundCopy();
|
||||
|
||||
return val;
|
||||
};
|
||||
private static Func<IReadOnlyDependencyContainer, object> getDependency(Type type, Type requestingType, bool permitNulls, CacheInfo info)
|
||||
=> dc => SourceGeneratorUtils.GetDependency(dc, type, requestingType, info.Name, info.Parent, permitNulls, true);
|
||||
}
|
||||
|
||||
public class PropertyNotWritableException : Exception
|
||||
|
||||
@@ -62,16 +62,35 @@ namespace osu.Framework.Utils
|
||||
/// <exception cref="DependencyNotRegisteredException">If the dependency is not in <paramref name="container"/>.</exception>
|
||||
public static T GetDependency<T>(IReadOnlyDependencyContainer container, Type callerType, string? cachedName, Type? cachedParent, bool allowNulls, bool rebindBindables)
|
||||
{
|
||||
object val = container.Get(typeof(T), new CacheInfo(cachedName, cachedParent));
|
||||
|
||||
if (val == null && !allowNulls)
|
||||
throw new DependencyNotRegisteredException(callerType, typeof(T));
|
||||
|
||||
if (rebindBindables && val is IBindable bindableVal)
|
||||
return (T)bindableVal.GetBoundCopy();
|
||||
object? val = GetDependency(container, typeof(T), callerType, cachedName, cachedParent, allowNulls, rebindBindables);
|
||||
|
||||
// `(int)(object)null` throws a NRE, so `default` is used instead.
|
||||
return val == null ? default! : (T)val;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves an object from an <see cref="IReadOnlyDependencyContainer"/>.
|
||||
/// </summary>
|
||||
/// <param name="container">The <see cref="IReadOnlyDependencyContainer"/> to retrieve the dependency from.</param>
|
||||
/// <param name="type">The type of the object to retrieve.</param>
|
||||
/// <param name="callerType">The type of object calling this method.</param>
|
||||
/// <param name="cachedName">The name of the object.</param>
|
||||
/// <param name="cachedParent">The parent of the object.</param>
|
||||
/// <param name="allowNulls">Whether the returned object is allowed to be <c>null</c>.</param>
|
||||
/// <param name="rebindBindables">If the object is a <see cref="IBindable"/>, whether it should be re-bound via <see cref="IBindable.GetBoundCopy"/>.</param>
|
||||
/// <returns>The object.</returns>
|
||||
/// <exception cref="DependencyNotRegisteredException">If the dependency is not in <paramref name="container"/>.</exception>
|
||||
public static object? GetDependency(IReadOnlyDependencyContainer container, Type type, Type callerType, string? cachedName, Type? cachedParent, bool allowNulls, bool rebindBindables)
|
||||
{
|
||||
object? val = container.Get(type, new CacheInfo(cachedName, cachedParent));
|
||||
|
||||
if (val == null && !allowNulls)
|
||||
throw new DependencyNotRegisteredException(callerType, type);
|
||||
|
||||
if (rebindBindables && val is IBindable bindableVal)
|
||||
return bindableVal.GetBoundCopy();
|
||||
|
||||
return val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user