4

ReactiveUI 内で組み込みの依存関係インジェクター/splat インジェクターを使用しています。

該当するデータ リポジトリを渡したいコンストラクターがあります。

他のフレームワークでは、インターフェイスでリフレクションを使用し、GetServices 呼び出しを使用してそれらのコンストラクターの要件を満たします。たとえば、現時点では、クラスを作成するためのこのヘルパー拡張メソッドがあります。

    /// <summary>
    /// Helper class for having a object's constructor automatically assigned by a "GetService" request.
    /// </summary>
    /// <param name="resolver">The resolver.</param>
    /// <param name="type">The type to register.</param>
    public static void Register<TConcrete, TInterface>(this IMutableDependencyResolver resolver)
        where TConcrete : class
    {
        var concreteType = typeof(TConcrete);

        // Must be a single constructor
        var constructors = concreteType.GetConstructors().Single();

        IList<object> values = new List<object>();

        foreach (var parameter in constructors.GetParameters())
        {
            if (parameter.ParameterType.IsInterface == false)
            {
                throw new InvalidOperationException($"The type {concreteType.Name} has constructor paramters that are not interfaces.");
            }

            values.Add(resolver.GetService(parameter.ParameterType));
        }

        resolver.Register(() => Activator.CreateInstance(concreteType, values.ToArray()), typeof(TInterface));
    }

このヘルパー クラスを使用する理由は、AppBootStrapper で次のことを行う必要がないようにするためです。

        dependencyResolver.Register(() => new SetupFlightViewModel(dependencyResolver.GetService<IScreen>(), dependencyResolver.GetService<IFlightsModel>(), dependencyResolver.GetService<IAirportsModel>()), typeof(ISetupFlightViewModel));

Splat/ReactiveUI フレームワークで自明でないことをしていないことを確認するだけで、既に提供されています。上記を実行するとパフォーマンス コストがかかることを認識しており、おそらく Expression Tree コンパイル式を使用して、毎回または何かのリフレクション コストを回避できます。

助けてくれてありがとう、グレン

4

3 に答える 3

5

Splat 依存関係リゾルバー (サービス レジストリ) は、すぐに使用できる非常に基本的なものであり、依存関係の挿入 (DI) を提供しません。

しかし、DI が好きなら (依存関係や設計の複雑さを隠すことができるので、誰もが好きというわけではありません。回避するためにその苦痛を感じることを好む人もいます)、先ほど行ったように、DI を簡単にプラグインすることができます。

ただし、impl に関する 1 つのコメントですがGetService、オブジェクトが作成されるまで実際の呼び出しを遅らせることをお勧めします (サービス レジストリの内容が時間の経過とともに変更され、Register順序付けが強制されないようにするため)。

var paramType = parameter.ParameterType;
values.Add(() => resolver.GetService(paramType));


... Activator.CreateInstance(concreteType, values.Select(cb => cb()).ToArray()) ...
于 2015-09-18T09:33:31.240 に答える
0

ReactiveUI を使い始めたばかりで、同じことをしようとしていました。StackOverflow でこの投稿を見つけて、解決策をつかみました。少し肉付けした後、コードを共有したいと思いました。これは私の検索で最初に表示された結果なので、ここに結果を投稿して、同じ道をたどっている人が私の努力の成果から恩恵を受けることができるようにしようと思いました.

public static class Bootstrapper
{
    public static void RegisterDependencies()
    {
        Locator.CurrentMutable.RegisterLazySingleton<ISettingsService>(CreateWithConstructorInjection<InMemorySettingsService>);
        Locator.CurrentMutable.Register<MainWindowViewModel>(CreateWithConstructorInjection<MainWindowViewModel>);
    }

    private static T CreateWithConstructorInjection<T>() where T : class
    {
        // Must be at most one constructor
        ConstructorInfo[] constructors = typeof(T).GetConstructors();
        if (constructors.Count() > 1)
            throw new InvalidOperationException($"Unable to create required dependency for {typeof(T).FullName}: type can not have more than one constructor, found {constructors.Count()}");

        // must not be null
        IEnumerable<Type> types = constructors.Single().GetParameters().Select(p => p.ParameterType).ToArray();
        if (Activator.CreateInstance(typeof(T), types.Select(GetService).ToArray()) is T t)
            return t;

        throw new InvalidOperationException($"Unable to create required dependency of type {typeof(T).FullName}: Activator.CreateInstance() returned null");
    }

    private static object GetService(Type type)
    {
        if (Locator.Current.GetService(type) is Object obj)
            return obj;

        throw new InvalidOperationException($"Unable to create required dependency of type {type.FullName}: IReadonlyDependencyResolver.GetService() returned null");
    }
}
于 2021-08-06T13:56:25.550 に答える