mirror of
https://github.com/goatcorp/Dalamud.git
synced 2026-02-21 07:17:45 +01:00
chore: convert Dalamud to file-scoped namespaces
This commit is contained in:
parent
b093323acc
commit
987ff8dc8f
368 changed files with 55081 additions and 55450 deletions
|
|
@ -1,25 +1,24 @@
|
|||
using System;
|
||||
|
||||
namespace Dalamud.IoC.Internal
|
||||
namespace Dalamud.IoC.Internal;
|
||||
|
||||
/// <summary>
|
||||
/// This attribute represents the current version of a module that is loaded in the Service Locator.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface)]
|
||||
internal class InterfaceVersionAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// This attribute represents the current version of a module that is loaded in the Service Locator.
|
||||
/// Initializes a new instance of the <see cref="InterfaceVersionAttribute"/> class.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface)]
|
||||
internal class InterfaceVersionAttribute : Attribute
|
||||
/// <param name="version">The current version.</param>
|
||||
public InterfaceVersionAttribute(string version)
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InterfaceVersionAttribute"/> class.
|
||||
/// </summary>
|
||||
/// <param name="version">The current version.</param>
|
||||
public InterfaceVersionAttribute(string version)
|
||||
{
|
||||
this.Version = new(version);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the service version.
|
||||
/// </summary>
|
||||
public Version Version { get; }
|
||||
this.Version = new(version);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the service version.
|
||||
/// </summary>
|
||||
public Version Version { get; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,33 +2,32 @@ using System;
|
|||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dalamud.IoC.Internal
|
||||
namespace Dalamud.IoC.Internal;
|
||||
|
||||
/// <summary>
|
||||
/// An object instance registered in the <see cref="ServiceContainer"/>.
|
||||
/// </summary>
|
||||
internal class ObjectInstance
|
||||
{
|
||||
/// <summary>
|
||||
/// An object instance registered in the <see cref="ServiceContainer"/>.
|
||||
/// Initializes a new instance of the <see cref="ObjectInstance"/> class.
|
||||
/// </summary>
|
||||
internal class ObjectInstance
|
||||
/// <param name="instanceTask">Weak reference to the underlying instance.</param>
|
||||
/// <param name="type">Type of the underlying instance.</param>
|
||||
public ObjectInstance(Task<WeakReference> instanceTask, Type type)
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ObjectInstance"/> class.
|
||||
/// </summary>
|
||||
/// <param name="instanceTask">Weak reference to the underlying instance.</param>
|
||||
/// <param name="type">Type of the underlying instance.</param>
|
||||
public ObjectInstance(Task<WeakReference> instanceTask, Type type)
|
||||
{
|
||||
this.InstanceTask = instanceTask;
|
||||
this.Version = type.GetCustomAttribute<InterfaceVersionAttribute>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current version of the instance, if it exists.
|
||||
/// </summary>
|
||||
public InterfaceVersionAttribute? Version { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a reference to the underlying instance.
|
||||
/// </summary>
|
||||
/// <returns>The underlying instance.</returns>
|
||||
public Task<WeakReference> InstanceTask { get; }
|
||||
this.InstanceTask = instanceTask;
|
||||
this.Version = type.GetCustomAttribute<InterfaceVersionAttribute>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current version of the instance, if it exists.
|
||||
/// </summary>
|
||||
public InterfaceVersionAttribute? Version { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a reference to the underlying instance.
|
||||
/// </summary>
|
||||
/// <returns>The underlying instance.</returns>
|
||||
public Task<WeakReference> InstanceTask { get; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,236 +7,235 @@ using System.Threading.Tasks;
|
|||
|
||||
using Dalamud.Logging.Internal;
|
||||
|
||||
namespace Dalamud.IoC.Internal
|
||||
namespace Dalamud.IoC.Internal;
|
||||
|
||||
/// <summary>
|
||||
/// A simple singleton-only IOC container that provides (optional) version-based dependency resolution.
|
||||
/// </summary>
|
||||
internal class ServiceContainer : IServiceProvider, IServiceType
|
||||
{
|
||||
private static readonly ModuleLog Log = new("SERVICECONTAINER");
|
||||
|
||||
private readonly Dictionary<Type, ObjectInstance> instances = new();
|
||||
|
||||
/// <summary>
|
||||
/// A simple singleton-only IOC container that provides (optional) version-based dependency resolution.
|
||||
/// Initializes a new instance of the <see cref="ServiceContainer"/> class.
|
||||
/// </summary>
|
||||
internal class ServiceContainer : IServiceProvider, IServiceType
|
||||
public ServiceContainer()
|
||||
{
|
||||
private static readonly ModuleLog Log = new("SERVICECONTAINER");
|
||||
}
|
||||
|
||||
private readonly Dictionary<Type, ObjectInstance> instances = new();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ServiceContainer"/> class.
|
||||
/// </summary>
|
||||
public ServiceContainer()
|
||||
/// <summary>
|
||||
/// Register a singleton object of any type into the current IOC container.
|
||||
/// </summary>
|
||||
/// <param name="instance">The existing instance to register in the container.</param>
|
||||
/// <typeparam name="T">The interface to register.</typeparam>
|
||||
public void RegisterSingleton<T>(Task<T> instance)
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(instance));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register a singleton object of any type into the current IOC container.
|
||||
/// </summary>
|
||||
/// <param name="instance">The existing instance to register in the container.</param>
|
||||
/// <typeparam name="T">The interface to register.</typeparam>
|
||||
public void RegisterSingleton<T>(Task<T> instance)
|
||||
this.instances[typeof(T)] = new(instance.ContinueWith(x => new WeakReference(x.Result)), typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an object.
|
||||
/// </summary>
|
||||
/// <param name="objectType">The type of object to create.</param>
|
||||
/// <param name="scopedObjects">Scoped objects to be included in the constructor.</param>
|
||||
/// <returns>The created object.</returns>
|
||||
public async Task<object?> CreateAsync(Type objectType, params object[] scopedObjects)
|
||||
{
|
||||
var ctor = this.FindApplicableCtor(objectType, scopedObjects);
|
||||
if (ctor == null)
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(instance));
|
||||
}
|
||||
|
||||
this.instances[typeof(T)] = new(instance.ContinueWith(x => new WeakReference(x.Result)), typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an object.
|
||||
/// </summary>
|
||||
/// <param name="objectType">The type of object to create.</param>
|
||||
/// <param name="scopedObjects">Scoped objects to be included in the constructor.</param>
|
||||
/// <returns>The created object.</returns>
|
||||
public async Task<object?> CreateAsync(Type objectType, params object[] scopedObjects)
|
||||
{
|
||||
var ctor = this.FindApplicableCtor(objectType, scopedObjects);
|
||||
if (ctor == null)
|
||||
{
|
||||
Log.Error("Failed to create {TypeName}, an eligible ctor with satisfiable services could not be found", objectType.FullName!);
|
||||
return null;
|
||||
}
|
||||
|
||||
// validate dependency versions (if they exist)
|
||||
var parameters = ctor.GetParameters().Select(p =>
|
||||
{
|
||||
var parameterType = p.ParameterType;
|
||||
var requiredVersion = p.GetCustomAttribute(typeof(RequiredVersionAttribute)) as RequiredVersionAttribute;
|
||||
return (parameterType, requiredVersion);
|
||||
}).ToList();
|
||||
|
||||
var versionCheck = parameters.All(p => CheckInterfaceVersion(p.requiredVersion, p.parameterType));
|
||||
|
||||
if (!versionCheck)
|
||||
{
|
||||
Log.Error("Failed to create {TypeName}, a RequestedVersion could not be satisfied", objectType.FullName!);
|
||||
return null;
|
||||
}
|
||||
|
||||
var resolvedParams =
|
||||
await Task.WhenAll(
|
||||
parameters
|
||||
.Select(async p =>
|
||||
{
|
||||
var service = await this.GetService(p.parameterType, scopedObjects);
|
||||
|
||||
if (service == null)
|
||||
{
|
||||
Log.Error("Requested service type {TypeName} was not available (null)", p.parameterType.FullName!);
|
||||
}
|
||||
|
||||
return service;
|
||||
}));
|
||||
|
||||
var hasNull = resolvedParams.Any(p => p == null);
|
||||
if (hasNull)
|
||||
{
|
||||
Log.Error("Failed to create {TypeName}, a requested service type could not be satisfied", objectType.FullName!);
|
||||
return null;
|
||||
}
|
||||
|
||||
var instance = FormatterServices.GetUninitializedObject(objectType);
|
||||
|
||||
if (!await this.InjectProperties(instance, scopedObjects))
|
||||
{
|
||||
Log.Error("Failed to create {TypeName}, a requested property service type could not be satisfied", objectType.FullName!);
|
||||
return null;
|
||||
}
|
||||
|
||||
ctor.Invoke(instance, resolvedParams);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inject <see cref="PluginInterfaceAttribute"/> interfaces into public or static properties on the provided object.
|
||||
/// The properties have to be marked with the <see cref="PluginServiceAttribute"/>.
|
||||
/// The properties can be marked with the <see cref="RequiredVersionAttribute"/> to lock down versions.
|
||||
/// </summary>
|
||||
/// <param name="instance">The object instance.</param>
|
||||
/// <param name="scopedObjects">Scoped objects.</param>
|
||||
/// <returns>Whether or not the injection was successful.</returns>
|
||||
public async Task<bool> InjectProperties(object instance, params object[] scopedObjects)
|
||||
{
|
||||
var objectType = instance.GetType();
|
||||
|
||||
var props = objectType.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public |
|
||||
BindingFlags.NonPublic).Where(x => x.GetCustomAttributes(typeof(PluginServiceAttribute)).Any()).Select(
|
||||
propertyInfo =>
|
||||
{
|
||||
var requiredVersion = propertyInfo.GetCustomAttribute(typeof(RequiredVersionAttribute)) as RequiredVersionAttribute;
|
||||
return (propertyInfo, requiredVersion);
|
||||
}).ToArray();
|
||||
|
||||
var versionCheck = props.All(x => CheckInterfaceVersion(x.requiredVersion, x.propertyInfo.PropertyType));
|
||||
|
||||
if (!versionCheck)
|
||||
{
|
||||
Log.Error("Failed to create {TypeName}, a RequestedVersion could not be satisfied", objectType.FullName!);
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var prop in props)
|
||||
{
|
||||
var service = await this.GetService(prop.propertyInfo.PropertyType, scopedObjects);
|
||||
|
||||
if (service == null)
|
||||
{
|
||||
Log.Error("Requested service type {TypeName} was not available (null)", prop.propertyInfo.PropertyType.FullName!);
|
||||
return false;
|
||||
}
|
||||
|
||||
prop.propertyInfo.SetValue(instance, service);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
object? IServiceProvider.GetService(Type serviceType) => this.GetService(serviceType);
|
||||
|
||||
private static bool CheckInterfaceVersion(RequiredVersionAttribute? requiredVersion, Type parameterType)
|
||||
{
|
||||
// if there's no required version, ignore it
|
||||
if (requiredVersion == null)
|
||||
return true;
|
||||
|
||||
// if there's no requested version, ignore it
|
||||
var declVersion = parameterType.GetCustomAttribute<InterfaceVersionAttribute>();
|
||||
if (declVersion == null)
|
||||
return true;
|
||||
|
||||
if (declVersion.Version == requiredVersion.Version)
|
||||
return true;
|
||||
|
||||
Log.Error(
|
||||
"Requested version {ReqVersion} does not match the implemented version {ImplVersion} for param type {ParamType}",
|
||||
requiredVersion.Version,
|
||||
declVersion.Version,
|
||||
parameterType.FullName!);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private async Task<object?> GetService(Type serviceType, object[] scopedObjects)
|
||||
{
|
||||
var singletonService = await this.GetService(serviceType);
|
||||
if (singletonService != null)
|
||||
{
|
||||
return singletonService;
|
||||
}
|
||||
|
||||
// resolve dependency from scoped objects
|
||||
var scoped = scopedObjects.FirstOrDefault(o => o.GetType() == serviceType);
|
||||
if (scoped == default)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return scoped;
|
||||
}
|
||||
|
||||
private async Task<object?> GetService(Type serviceType)
|
||||
{
|
||||
if (!this.instances.TryGetValue(serviceType, out var service))
|
||||
return null;
|
||||
|
||||
var instance = await service.InstanceTask;
|
||||
return instance.Target;
|
||||
}
|
||||
|
||||
private ConstructorInfo? FindApplicableCtor(Type type, object[] scopedObjects)
|
||||
{
|
||||
// get a list of all the available types: scoped and singleton
|
||||
var types = scopedObjects
|
||||
.Select(o => o.GetType())
|
||||
.Union(this.instances.Keys)
|
||||
.ToArray();
|
||||
|
||||
var ctors = type.GetConstructors(BindingFlags.Public | BindingFlags.Instance);
|
||||
foreach (var ctor in ctors)
|
||||
{
|
||||
if (this.ValidateCtor(ctor, types))
|
||||
{
|
||||
return ctor;
|
||||
}
|
||||
}
|
||||
|
||||
Log.Error("Failed to create {TypeName}, an eligible ctor with satisfiable services could not be found", objectType.FullName!);
|
||||
return null;
|
||||
}
|
||||
|
||||
private bool ValidateCtor(ConstructorInfo ctor, Type[] types)
|
||||
// validate dependency versions (if they exist)
|
||||
var parameters = ctor.GetParameters().Select(p =>
|
||||
{
|
||||
var parameters = ctor.GetParameters();
|
||||
foreach (var parameter in parameters)
|
||||
var parameterType = p.ParameterType;
|
||||
var requiredVersion = p.GetCustomAttribute(typeof(RequiredVersionAttribute)) as RequiredVersionAttribute;
|
||||
return (parameterType, requiredVersion);
|
||||
}).ToList();
|
||||
|
||||
var versionCheck = parameters.All(p => CheckInterfaceVersion(p.requiredVersion, p.parameterType));
|
||||
|
||||
if (!versionCheck)
|
||||
{
|
||||
Log.Error("Failed to create {TypeName}, a RequestedVersion could not be satisfied", objectType.FullName!);
|
||||
return null;
|
||||
}
|
||||
|
||||
var resolvedParams =
|
||||
await Task.WhenAll(
|
||||
parameters
|
||||
.Select(async p =>
|
||||
{
|
||||
var service = await this.GetService(p.parameterType, scopedObjects);
|
||||
|
||||
if (service == null)
|
||||
{
|
||||
Log.Error("Requested service type {TypeName} was not available (null)", p.parameterType.FullName!);
|
||||
}
|
||||
|
||||
return service;
|
||||
}));
|
||||
|
||||
var hasNull = resolvedParams.Any(p => p == null);
|
||||
if (hasNull)
|
||||
{
|
||||
Log.Error("Failed to create {TypeName}, a requested service type could not be satisfied", objectType.FullName!);
|
||||
return null;
|
||||
}
|
||||
|
||||
var instance = FormatterServices.GetUninitializedObject(objectType);
|
||||
|
||||
if (!await this.InjectProperties(instance, scopedObjects))
|
||||
{
|
||||
Log.Error("Failed to create {TypeName}, a requested property service type could not be satisfied", objectType.FullName!);
|
||||
return null;
|
||||
}
|
||||
|
||||
ctor.Invoke(instance, resolvedParams);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inject <see cref="PluginInterfaceAttribute"/> interfaces into public or static properties on the provided object.
|
||||
/// The properties have to be marked with the <see cref="PluginServiceAttribute"/>.
|
||||
/// The properties can be marked with the <see cref="RequiredVersionAttribute"/> to lock down versions.
|
||||
/// </summary>
|
||||
/// <param name="instance">The object instance.</param>
|
||||
/// <param name="scopedObjects">Scoped objects.</param>
|
||||
/// <returns>Whether or not the injection was successful.</returns>
|
||||
public async Task<bool> InjectProperties(object instance, params object[] scopedObjects)
|
||||
{
|
||||
var objectType = instance.GetType();
|
||||
|
||||
var props = objectType.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public |
|
||||
BindingFlags.NonPublic).Where(x => x.GetCustomAttributes(typeof(PluginServiceAttribute)).Any()).Select(
|
||||
propertyInfo =>
|
||||
{
|
||||
var contains = types.Contains(parameter.ParameterType);
|
||||
if (!contains)
|
||||
{
|
||||
Log.Error("Failed to validate {TypeName}, unable to find any services that satisfy the type", parameter.ParameterType.FullName!);
|
||||
return false;
|
||||
}
|
||||
var requiredVersion = propertyInfo.GetCustomAttribute(typeof(RequiredVersionAttribute)) as RequiredVersionAttribute;
|
||||
return (propertyInfo, requiredVersion);
|
||||
}).ToArray();
|
||||
|
||||
var versionCheck = props.All(x => CheckInterfaceVersion(x.requiredVersion, x.propertyInfo.PropertyType));
|
||||
|
||||
if (!versionCheck)
|
||||
{
|
||||
Log.Error("Failed to create {TypeName}, a RequestedVersion could not be satisfied", objectType.FullName!);
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var prop in props)
|
||||
{
|
||||
var service = await this.GetService(prop.propertyInfo.PropertyType, scopedObjects);
|
||||
|
||||
if (service == null)
|
||||
{
|
||||
Log.Error("Requested service type {TypeName} was not available (null)", prop.propertyInfo.PropertyType.FullName!);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
prop.propertyInfo.SetValue(instance, service);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
object? IServiceProvider.GetService(Type serviceType) => this.GetService(serviceType);
|
||||
|
||||
private static bool CheckInterfaceVersion(RequiredVersionAttribute? requiredVersion, Type parameterType)
|
||||
{
|
||||
// if there's no required version, ignore it
|
||||
if (requiredVersion == null)
|
||||
return true;
|
||||
|
||||
// if there's no requested version, ignore it
|
||||
var declVersion = parameterType.GetCustomAttribute<InterfaceVersionAttribute>();
|
||||
if (declVersion == null)
|
||||
return true;
|
||||
|
||||
if (declVersion.Version == requiredVersion.Version)
|
||||
return true;
|
||||
|
||||
Log.Error(
|
||||
"Requested version {ReqVersion} does not match the implemented version {ImplVersion} for param type {ParamType}",
|
||||
requiredVersion.Version,
|
||||
declVersion.Version,
|
||||
parameterType.FullName!);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private async Task<object?> GetService(Type serviceType, object[] scopedObjects)
|
||||
{
|
||||
var singletonService = await this.GetService(serviceType);
|
||||
if (singletonService != null)
|
||||
{
|
||||
return singletonService;
|
||||
}
|
||||
|
||||
// resolve dependency from scoped objects
|
||||
var scoped = scopedObjects.FirstOrDefault(o => o.GetType() == serviceType);
|
||||
if (scoped == default)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return scoped;
|
||||
}
|
||||
|
||||
private async Task<object?> GetService(Type serviceType)
|
||||
{
|
||||
if (!this.instances.TryGetValue(serviceType, out var service))
|
||||
return null;
|
||||
|
||||
var instance = await service.InstanceTask;
|
||||
return instance.Target;
|
||||
}
|
||||
|
||||
private ConstructorInfo? FindApplicableCtor(Type type, object[] scopedObjects)
|
||||
{
|
||||
// get a list of all the available types: scoped and singleton
|
||||
var types = scopedObjects
|
||||
.Select(o => o.GetType())
|
||||
.Union(this.instances.Keys)
|
||||
.ToArray();
|
||||
|
||||
var ctors = type.GetConstructors(BindingFlags.Public | BindingFlags.Instance);
|
||||
foreach (var ctor in ctors)
|
||||
{
|
||||
if (this.ValidateCtor(ctor, types))
|
||||
{
|
||||
return ctor;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private bool ValidateCtor(ConstructorInfo ctor, Type[] types)
|
||||
{
|
||||
var parameters = ctor.GetParameters();
|
||||
foreach (var parameter in parameters)
|
||||
{
|
||||
var contains = types.Contains(parameter.ParameterType);
|
||||
if (!contains)
|
||||
{
|
||||
Log.Error("Failed to validate {TypeName}, unable to find any services that satisfy the type", parameter.ParameterType.FullName!);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
using System;
|
||||
|
||||
namespace Dalamud.IoC
|
||||
namespace Dalamud.IoC;
|
||||
|
||||
/// <summary>
|
||||
/// This attribute indicates whether the decorated class should be exposed to plugins via IoC.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class PluginInterfaceAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// This attribute indicates whether the decorated class should be exposed to plugins via IoC.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class PluginInterfaceAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,14 +2,13 @@
|
|||
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Dalamud.IoC
|
||||
namespace Dalamud.IoC;
|
||||
|
||||
/// <summary>
|
||||
/// This attribute indicates whether an applicable service should be injected into the plugin.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
[MeansImplicitUse(ImplicitUseKindFlags.Assign)]
|
||||
public class PluginServiceAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// This attribute indicates whether an applicable service should be injected into the plugin.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
[MeansImplicitUse(ImplicitUseKindFlags.Assign)]
|
||||
public class PluginServiceAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +1,24 @@
|
|||
using System;
|
||||
|
||||
namespace Dalamud.IoC
|
||||
namespace Dalamud.IoC;
|
||||
|
||||
/// <summary>
|
||||
/// This attribute indicates the version of a service module that is required for the plugin to load.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property)]
|
||||
public class RequiredVersionAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// This attribute indicates the version of a service module that is required for the plugin to load.
|
||||
/// Initializes a new instance of the <see cref="RequiredVersionAttribute"/> class.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property)]
|
||||
public class RequiredVersionAttribute : Attribute
|
||||
/// <param name="version">The required version.</param>
|
||||
public RequiredVersionAttribute(string version)
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RequiredVersionAttribute"/> class.
|
||||
/// </summary>
|
||||
/// <param name="version">The required version.</param>
|
||||
public RequiredVersionAttribute(string version)
|
||||
{
|
||||
this.Version = new(version);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the required version.
|
||||
/// </summary>
|
||||
public Version Version { get; }
|
||||
this.Version = new(version);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the required version.
|
||||
/// </summary>
|
||||
public Version Version { get; }
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue