C# 减少不断增加的构造函数服务参数

C# 减少不断增加的构造函数服务参数,c#,dependency-injection,autofac,autofac-configuration,C#,Dependency Injection,Autofac,Autofac Configuration,我对使用Autofac还是一个新手,我对我正在使用的构造函数注入方法感到困扰。以下是场景: 我目前有两个类继承了IForms接口。每个类都有自己的接口 public interface IForms { long CreateNewForm(FormData data); FormData RetrieveFormById(long id); } public interface IFormA : IForms { } public interface IFormB : I

我对使用Autofac还是一个新手,我对我正在使用的构造函数注入方法感到困扰。以下是场景:

我目前有两个类继承了IForms接口。每个类都有自己的接口

public interface IForms 
{
    long CreateNewForm(FormData data);
    FormData RetrieveFormById(long id);
}

public interface IFormA : IForms
{ }

public interface IFormB : IForms
{ }
现在我有一个类来处理这个问题,如下所示:

public class ApplicationForms : IApplicationForms
{
    private readonly IFormA _formA;
    private readonly IFormB _formB;

    public ApplicationForms(IFormA formA, IFormB formB)
    {
        _formA = formA;
        _formB = formB;
    }

    public void SubmitApplicationForm(FormData data)
    {
        switch(data.FormType)
        {
            case FormType.FormA:
                _formA.CreateNewForm(data);
                break;
            case FormType.FormB:
                _formB.CreateNewForm(data);
                break;
        }
    }
}
public class ApplicationForms : IApplicationForms
{
    private readonly GetFormByTypeFunction _getFormByType;

    public ApplicationForms(GetFormByTypeFunction getFormByType)
    {
        _getFormByType = getFormByType;
    }

    public void SubmitApplicationForm(FormData data)
    {
        var form = _getFormByType(data.FormType);
        form.CreateNewForm(data);
    }
}
builder.Register<GetFormByTypeFunction>(context => formType =>
{
    switch (formType)
    {
        case FormType.Type1:
        {
            return context.Resolve<FormOne>();
        }
        case FormType.Type2:
        {
            return context.Resolve<FormTwo>();
        }
        default:
            throw new InvalidOperationException("Unknown form type");
    }
});
现在有可能会有另外两种形式,比如FormC,FormD,FormE。这里将要发生的是ApplicationForms构造函数中还有3个构造函数参数

有没有办法将所有构造函数参数组合成一个参数?我可以看出,它最终肯定会看起来很难看。

因为有一个通用的IForms接口,所以您可以插入一个枚举

这看起来是战略模式的一个很好的候选者

我建议重构基本接口,以便能够识别它是什么类型的表单

public interface IForms {
    FormType FormType { get; }
    long CreateNewForm(FormData data);
    FormData RetrieveFormById(long id);
}
并更新依赖类

public class ApplicationForms : IApplicationForms {
    private readonly IEnumerable<IForms> forms;

    public ApplicationForms(IEnumerable<IForms> forms) {
        this.forms = forms;
    }

    public void SubmitApplicationForm(FormData data) {
        var form = forms.FirstOrDefault(_ => _.FormType == data.FormType);
        if(form != null)
            form.CreateNewForm(data);

        //...
    }
}

现在,无论添加了多少表单,该类都可以执行而无需修改。

您描述的问题是,您有许多表单,但在运行时需要一个特定的表单,因此您不希望注入所有表单。对于抽象工厂来说,这可能是一个很好的场景

我们通常使用单个方法将工厂表示为接口,但也可以使用委托:

public delegate IForm GetFormByTypeFunction(FormType formType);
现在,您的类如下所示:

public class ApplicationForms : IApplicationForms
{
    private readonly IFormA _formA;
    private readonly IFormB _formB;

    public ApplicationForms(IFormA formA, IFormB formB)
    {
        _formA = formA;
        _formB = formB;
    }

    public void SubmitApplicationForm(FormData data)
    {
        switch(data.FormType)
        {
            case FormType.FormA:
                _formA.CreateNewForm(data);
                break;
            case FormType.FormB:
                _formB.CreateNewForm(data);
                break;
        }
    }
}
public class ApplicationForms : IApplicationForms
{
    private readonly GetFormByTypeFunction _getFormByType;

    public ApplicationForms(GetFormByTypeFunction getFormByType)
    {
        _getFormByType = getFormByType;
    }

    public void SubmitApplicationForm(FormData data)
    {
        var form = _getFormByType(data.FormType);
        form.CreateNewForm(data);
    }
}
builder.Register<GetFormByTypeFunction>(context => formType =>
{
    switch (formType)
    {
        case FormType.Type1:
        {
            return context.Resolve<FormOne>();
        }
        case FormType.Type2:
        {
            return context.Resolve<FormTwo>();
        }
        default:
            throw new InvalidOperationException("Unknown form type");
    }
});
现在的问题是如何实施工厂。它可能仍然有一个switch语句或一些看起来不太优雅的语句,但这没关系。工厂的要点是,不管它如何工作,创建和/或选择实现的业务都会从依赖于实现的类中移出

您可以像这样向Autofac注册代理:

public class ApplicationForms : IApplicationForms
{
    private readonly IFormA _formA;
    private readonly IFormB _formB;

    public ApplicationForms(IFormA formA, IFormB formB)
    {
        _formA = formA;
        _formB = formB;
    }

    public void SubmitApplicationForm(FormData data)
    {
        switch(data.FormType)
        {
            case FormType.FormA:
                _formA.CreateNewForm(data);
                break;
            case FormType.FormB:
                _formB.CreateNewForm(data);
                break;
        }
    }
}
public class ApplicationForms : IApplicationForms
{
    private readonly GetFormByTypeFunction _getFormByType;

    public ApplicationForms(GetFormByTypeFunction getFormByType)
    {
        _getFormByType = getFormByType;
    }

    public void SubmitApplicationForm(FormData data)
    {
        var form = _getFormByType(data.FormType);
        form.CreateNewForm(data);
    }
}
builder.Register<GetFormByTypeFunction>(context => formType =>
{
    switch (formType)
    {
        case FormType.Type1:
        {
            return context.Resolve<FormOne>();
        }
        case FormType.Type2:
        {
            return context.Resolve<FormTwo>();
        }
        default:
            throw new InvalidOperationException("Unknown form type");
    }
});

我喜欢工厂代表的想法。省去了初始化所有实现的麻烦。很好。如果我注入所有表单,会有任何性能影响或暗示吗?我也想了解这一点。如果只需要一个实例,那么注入所有实例可能效率较低,但如果每次都不创建新实例,则效率会降低。即使您正在创建新实例,我也不会太担心性能。如果您将它们全部注入,则意味着您的类依赖于它们。但你不需要所有这些,你需要一个基于论点的。如果你按照类的需要和行为来建模,就会更清楚。另外,如果另一个类需要相同的行为,您不想复制逻辑。@Musikero31如果您真正需要的只是一个基于条件的实现,我建议使用这种方法来解决所有注入实现。即使FormType来自客户端?此外,注册来自Global.asax。所以我不知道结果会怎样。