我可以使用哪种模式来避免实例化管道中不必要的块?

Don*_*ong 5 c# design-patterns pipeline instance

我的ASP.NET Core应用程序正在使用我们自己设计的管道来处理请求。每个管道包含1个以上的块,并且块数没有任何限制。实际实例中最多可以有200个以上的块,管道将按照配置中的顺序通过所有块,例如:

Pipeline<DoActionsPipeline>().AddBlock<DoActionAddUserBlock>().AddBlock<DoActionAddUserToRoleBlock>()... 
Run Code Online (Sandbox Code Playgroud)

像上述的例子(只是一个例子),并有在该管道中配置200+块,这些块可以是DoActionAddUserBlockDoActionAddUserToRoleBlockDoActionAddAddressToUserBlock,等。许多动作混合在一个管道中。(请不要问为什么混合它们,这只是一个例子,对我的问题无关紧要。)

对于此示例,在每个块中,我们将首先检查动作名称,如果匹配,则运行逻辑。但这很糟糕,它必须实例化所有块并通过所有这些块来完成请求。

这是示例代码,虽然不是很好,但它显示了我的痛苦:

public class DoActionAddUserBlock : BaseBlock<User, User, Context>
{
    public override User Execute(User arg, Context context)
    {
        if (context.ActionName != "AddUser")
        {
            return arg;
        }

        return AddUser(arg);
    }

    protected User AddUser(User user)
    {
        return user;
    }
}

public abstract class BaseBlock<TArg, TResult, TContext>
{
    public abstract TResult Execute(TArg arg, TContext context);
}

public class Context
{
    public string ActionName { get; set; }
}
public class User
{

}
Run Code Online (Sandbox Code Playgroud)

我想避免按条件实例化块,我认为它应该处于管道配置级别。我怎样才能做到这一点?属性?或其他。

[Condition("Action==AddUser")] // or [Action("AddUser")] // or [TypeOfArg("User")]
public class DoActionAddUserBlock : BaseBlock<User, User, Context>
{
    public override User Execute(User arg, Context context)
    {
        return AddUser(arg);
    }

    //...
}
Run Code Online (Sandbox Code Playgroud)

T-m*_*oty 2

请向我们展示Pipeline<T>()方法(是方法还是类?),因为它对于准确的答案至关重要。

无论如何,我想尽力利用当前的信息。

您的目标是“我想有条件地实例化块”,因此您必须在实例外上下文中移动您的条件,您可以使用属性来执行此操作:

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class ActionNameAttribute : Attribute
{
    public ActionNameAttribute(string name)
    {
        this.Name = name;
    }

    public string Name { get; }
}

[ActionName(nameof(AddUser))]
public class DoActionAddUserBlock : BaseBlock<User, User, Context>
{
    public override User Execute(User arg, Context context)
    {
        return AddUser(arg);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,检查该.AddBlock<T>()方法(我猜,是类似的东西):

public YourUnknownType<T> AddBlock<TBlock>()
{
    var type = typeof(TBlock);
    var attributes = attributes.GetCustomAttributes(typeof(ActionNameAttribute), inherit: true); // or false if you don't need inheritation
    var attribute = attributes.FirstOrDefault() as ActionNameAttribute;

    if (attribute.Name == this.Context.ActioName)
    {
        // place here the block init
    }

    return AnythingYouActuallyReturn();
}
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助!