Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/273.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 具有大量DI参数的多态抽象类_C#_Unit Testing_Dependency Injection_Autofac - Fatal编程技术网

C# 具有大量DI参数的多态抽象类

C# 具有大量DI参数的多态抽象类,c#,unit-testing,dependency-injection,autofac,C#,Unit Testing,Dependency Injection,Autofac,我经常遇到这样的问题:有一个抽象类来完成所有繁重的工作,然后我有很多多态类来定制抽象以满足特定的需要。抽象通常需要很多参数,因此它们都必须从所有多态类传递 public class FooComplex : AbstractFoo { public FooComplex(IBarAwesome awesome, IBarCool cool, ...) : base(IBarAwesome awesome, IBarCool cool, ...) { } ...a lot of o

我经常遇到这样的问题:有一个抽象类来完成所有繁重的工作,然后我有很多多态类来定制抽象以满足特定的需要。抽象通常需要很多参数,因此它们都必须从所有多态类传递

public class FooComplex : AbstractFoo {
    public FooComplex(IBarAwesome awesome, IBarCool cool, ...) : base(IBarAwesome awesome, IBarCool cool, ...) { }
    ...a lot of overriding abstracts
}

public class FooSimple : AbstractFoo
{
    public FooSimple(IBarAwesome awesome, IBarCool cool, ...) : base(IBarAwesome awesome, IBarCool cool, ...) { }
    ...little bit of overriding abstracts
}

public class AbstractFoo
{
    public AbstractFoo(IBarAwesome awesome, IBarCool cool, ...)
    ...heavy lifting
}
我能做些什么来不通过所有这些东西,但能够对它们进行单元测试吗?我一直被教导这样做

var awesome = container.Resolve<IBarAwesome>();
var awesome=container.Resolve();
比如说,构造函数是一种糟糕的做法


我之所以想找到解决办法,因为我必须复制相同的参数并将其传递到许多多态子类中,所以将任何新的参数传递到抽象类中会变得越来越困难。

我相信这与注释中提到的@C.Evenhuis类似,它将构造函数参数抽象到一个公共接口中,以便它们可以作为单个构造函数参数,易于测试

具体类别:

public class FooComplex : AbstractFoo
{
    public FooComplex(ComplexParam complexParam) : base(complexParam)
    {}
}

public class FooSimple : AbstractFoo
{
    public FooSimple(SimpleParam simpleParam) : base(simpleParam)
    {}
}
public abstract class AbstractFoo
{
 protected AbstractFoo(IParam parameter) { }
}
public interface IBarCool : IBar
{}

public interface IBarAwesome : IBar
{}

public interface IBar
{}

public interface IParam
{
    IEnumerable<IBar> Param { get; }
}
单一通用混凝土等级(可选)

使用该类,您可以将任何类型传递到继承
iparms
的构造函数中,并可能消除对
foomplex
FooSimple
的需要

public class Foo<T> : AbstractFoo where T : IParam
{
    public Foo(T param) : base(param)
    { }
}
接口:

public class FooComplex : AbstractFoo
{
    public FooComplex(ComplexParam complexParam) : base(complexParam)
    {}
}

public class FooSimple : AbstractFoo
{
    public FooSimple(SimpleParam simpleParam) : base(simpleParam)
    {}
}
public abstract class AbstractFoo
{
 protected AbstractFoo(IParam parameter) { }
}
public interface IBarCool : IBar
{}

public interface IBarAwesome : IBar
{}

public interface IBar
{}

public interface IParam
{
    IEnumerable<IBar> Param { get; }
}

需要做的就是:

public interface IAbstractParams
{
   IBarAwesome awesome { get; } 
   IBarCool cool { get; }
   ... 
}

public class FooComplex : AbstractFoo 
{
    public FooComplex(IAbstractParams params) : base(params) { }
    ...a lot of overriding abstracts
}

public class FooSimple : AbstractFoo
{
    public FooSimple(IAbstractParams params) : base(params) { }
    ...little bit of overriding abstracts
}

public class AbstractFoo
{
    protected readonly IBarAwesome _awesome;
    protected readonly IBarCool _cool;

    public AbstractFoo(IAbstractParams params)
    {
     _awesome = params.awesome;
     _cool = params.cool;
    }

    ...heavy lifting
}
然后,您需要添加nuget软件包Autofac.Extras.AggregateService,并将此行添加到生成器中:

builder.RegisterAggregateService<IAbstractParams>();
builder.RegisterAggregateService();
感谢@Travis Illig@C.Evenhuis帮助我想出这个解决方案


对于同一问题的更复杂的解决方案,请查看@Kitson88

如果您希望这些参数随时间变化,一种解决方案是将它们放在一个
AbstractFooParameters
类中,具体类作为单个参数传递。不确定这是否是你想要的。这能用于DI吗?我不知道autofac,但它应该与构造函数注入一起工作,就像任何其他构造函数参数一样。我真的喜欢这个解决方案。你能把它作为答案发布吗?@IanOverton,我同意C.Evenhuis的解决方案是我关于如何解决这个问题的最初想法,但是实现在很大程度上取决于这些参数的上下文,以及您试图从“使用Autofac解决此问题”的角度实现什么,允许您定义一个接口,其中所需参数是接口上的属性。Autofac将动态生成接口的具体实现,并为您填充属性@TravisIllig没有使用Autofac的乐趣。现在只是浏览一下文档…非常令人印象深刻。参数列表在两个类中是相同的,而不是动态列表。只是课程的细节不同。特拉维斯说的很有趣,我得试试。它将使我不需要一个具体的类来完成我想做的事情。尽管我不需要这种解决这个问题的方法,但这绝对是一个很棒的方法,我必须找到使用它的地方。