Skip to content

Commit

Permalink
Experimentally implement Microsoft Dependency Injection.
Browse files Browse the repository at this point in the history
  • Loading branch information
Emzi0767 committed Nov 3, 2017
1 parent faeace0 commit 7a349be
Show file tree
Hide file tree
Showing 12 changed files with 110 additions and 278 deletions.
2 changes: 1 addition & 1 deletion .nuget/NuGet.config
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key=".NET Core (MyGet)" value="https://dotnet.myget.org/F/dotnet-core/api/v3/index.json" />
Expand Down
12 changes: 12 additions & 0 deletions DSharpPlus.CommandsNext/Attributes/DontInjectAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System;

namespace DSharpPlus.CommandsNext.Attributes
{
/// <summary>
/// Prevents this field or property from having its value injected by dependency injection.
/// </summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
public class DontInjectAttribute : Attribute
{
}
}
9 changes: 5 additions & 4 deletions DSharpPlus.CommandsNext/CommandsNextConfiguration.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using DSharpPlus.CommandsNext.Attributes;
using DSharpPlus.CommandsNext.Converters;
Expand Down Expand Up @@ -77,11 +78,11 @@ public sealed class CommandsNextConfiguration
public bool EnableDms { internal get; set; } = true;

/// <summary>
/// <para>Sets the dependency collection for this CommandsNext instance.</para>
/// <para>Objects in this collection are used when instantiating command modules. This allows passing data around without resorting to static members.</para>
/// <para>Sets the service provider for this CommandsNext instance.</para>
/// <para>Objects in this provider are used when instantiating command modules. This allows passing data around without resorting to static members.</para>
/// <para>Defaults to null.</para>
/// </summary>
public DependencyCollection Dependencies { internal get; set; } = null;
public IServiceProvider Services { internal get; set; } = null;

/// <summary>
/// <para>Gets whether any extra arguments passed to commands should be ignored or not. If this is set to false, extra arguments will throw, otherwise they will be ignored.</para>
Expand Down
49 changes: 40 additions & 9 deletions DSharpPlus.CommandsNext/CommandsNextExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using DSharpPlus.CommandsNext.Exceptions;
using DSharpPlus.Entities;
using DSharpPlus.EventArgs;
using Microsoft.Extensions.DependencyInjection;

namespace DSharpPlus.CommandsNext
{
Expand Down Expand Up @@ -51,10 +52,10 @@ private Task OnCommandErrored(CommandErrorEventArgs e)
private const string GROUP_COMMAND_METHOD_NAME = "ExecuteGroupAsync";

/// <summary>
/// Gets the dependency collection this CommandsNext module was configured with.
/// Gets the service provider this CommandsNext module was configured with.
/// </summary>
public DependencyCollection Dependencies
=> this.Config.Dependencies;
public IServiceProvider Services
=> this.Config.Services;

internal CommandsNextExtension(CommandsNextConfiguration cfg)
{
Expand Down Expand Up @@ -209,8 +210,7 @@ public async Task HandleCommandsAsync(MessageCreateEventArgs e)
//RawArguments = new ReadOnlyCollection<string>(arg.ToList()),
Config = this.Config,
RawArgumentString = rrg,
CommandsNext = this,
Dependencies = this.Config.Dependencies
CommandsNext = this
};

if (cmd == null)
Expand Down Expand Up @@ -534,16 +534,47 @@ private object CreateInstance(Type t)
var constr = cs[0];
var prms = constr.GetParameters();
var args = new object[prms.Length];
var deps = this.Config.Dependencies;
var deps = this.Config.Services;

if (prms.Length != 0 && deps == null)
throw new InvalidOperationException("Dependency collection needs to be specified for parametered constructors.");


// inject via constructor
if (prms.Length != 0)
for (var i = 0; i < args.Length; i++)
args[i] = deps.GetDependency(prms[i].ParameterType);
args[i] = deps.GetRequiredService(prms[i].ParameterType);

var module = Activator.CreateInstance(t, args);

// inject into properties
var props = ti.DeclaredProperties.Where(xp => xp.CanWrite && xp.SetMethod != null && !xp.SetMethod.IsStatic && xp.SetMethod.IsPublic);
foreach (var prop in props)
{
if (prop.GetCustomAttribute<DontInjectAttribute>() != null)
continue;

var srv = deps.GetService(prop.PropertyType);
if (srv == null)
continue;

prop.SetValue(module, srv);
}

// inject into fields
var fields = ti.DeclaredFields.Where(xf => !xf.IsInitOnly && !xf.IsStatic && xf.IsPublic);
foreach (var field in fields)
{
if (field.GetCustomAttribute<DontInjectAttribute>() != null)
continue;

var srv = deps.GetService(field.FieldType);
if (srv == null)
continue;

field.SetValue(module, srv);
}

return Activator.CreateInstance(t, args);
return module;
}

private void AddToCommandDictionary(Command cmd)
Expand Down
4 changes: 4 additions & 0 deletions DSharpPlus.CommandsNext/DSharpPlus.CommandsNext.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
<PackageTags>discord discord-api bots discord-bots chat dsharp dsharpplus csharp dotnet vb-net fsharp commands commandsnext</PackageTags>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Emzi0767.Microsoft.DependencyInjection" Version="2.0.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\DSharpPlus\DSharpPlus.csproj" />
</ItemGroup>
Expand Down
3 changes: 1 addition & 2 deletions DSharpPlus.CommandsNext/Entities/CommandGroup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,7 @@ public override async Task<CommandResult> ExecuteAsync(CommandContext ctx)
Command = cmd,
Config = ctx.Config,
RawArgumentString = x,
CommandsNext = ctx.CommandsNext,
Dependencies = ctx.Dependencies
CommandsNext = ctx.CommandsNext
};

var fchecks = await cmd.RunChecksAsync(xctx, false).ConfigureAwait(false);
Expand Down
71 changes: 0 additions & 71 deletions DSharpPlus.CommandsNext/Entities/DependencyCollection.cs

This file was deleted.

171 changes: 0 additions & 171 deletions DSharpPlus.CommandsNext/Entities/DependencyCollectionBuilder.cs

This file was deleted.

Loading

0 comments on commit 7a349be

Please sign in to comment.