我使用structuremap.net作为我的容器。我想将类的所有依赖项作为依赖项对象传递,而不是每个依赖项传递一个参数。
// Dependencies of Controller
class Dependencies {
public IUserDatabase UserDatabase { get; set; }
public IProductDatabase ProductDatabase { get; set; }
// more dependencies ...
}
class Controller {
Dependencies _d;
Controller(Dependencies dependencies){
this._d = dependencies;
}
public ActionResult Action() {
var user = _this._d.GetUserById(10);
var product = _this._d.GetProductById(20);
// ...
}
}
如何通过结构图构建类IUserDatabase
的实例时,如何使用setter injection(IProductDatabase
,Dependencies
等)自动设置所有依赖项?
var container = new Container();
// How to configure this in a generic way?
var dependencies = container.GetInstance<Dependencies>();
修改
我的第一个例子似乎没有说明为什么我想要一个完整的对象的setter注入以及为什么这不是一个糟糕的设计选择。
我们有一个自定义Web框架,它采用了ASP.NET MVC的许多原则,但在很多方面也有所不同。与ASP.NET MVC一样,我们在控制器中也有动作和控制器以及组操作。典型代码如下所示:
class MyController {
public IUserDatabase _userDatabase;
public IProductDatabase _productDatabase;
public IRatingDatabase _ratingDatabase;
public ICommentsDatabase _commentsDatabase;
MyController(IUserDatabase userDatabase, IUserDatabase productDatabase, IRatingDatabase ratingDatabase, ICommentsDatabase commentsDatabase){
_userDatabase = userDatabase;
_productDatabase = productDatabase;
_ratingDatabase = ratingDatabase;
_commentsDatabase = commentsDatabase;
}
public ActionResult Action1(){
var user = _userDatabase.GetById(10);
var product = _productDatabase.GetById(20);
}
public ActionResult Action2() {
var ratings = _ratingDatabase.GetById(20);
var comments = _commentsDatabase.GetById(20);
}
}
此控制器有两个动作。这些操作都没有使用控制器的所有依赖项。此外,通过构造函数注入将依赖项传递给控制器会产生很多噪音。
相反,我想将一个动作的依赖项直接作为参数传递给该动作。我们有自己的路由,可以轻松支持此功能。
class Action1Dependencies {
public IUserDatabase UserDatabase {get; set;}
public IProductDatabase ProductDatabase {get; set;}
}
class Action2Dependencies {
public IRatingDatabase RatingDatabase {get; set;}
public ICommentsDatabase CommentsDatabase {get; set;}
}
class MyController {
public static ActionResult Action1(Action1Dependencies d){
var user = d.UserDatabase.GetById(10);
var product = d.ProductDatabase.GetById(20);
}
public static ActionResult Action2(Action2Dependencies d) {
var ratings = d.RatingDatabase.GetById(20);
var comments = d.CommentsDatabase.GetById(20);
}
}
因此,我想进行var dependencies = container.GetInstance<Action2Dependencies>();
之类的调用,并让StructureMap通过setter注入设置Action2Dependencies
的所有属性。
使用C#7并支持tuples,上面的代码也可能成为
class MyController {
public static ActionResult Action1((IUserDatabase UserDatabase, IProductDatabase ProductDatabase) d){
var user = d.UserDatabase.GetById(10);
var product = d.ProductDatabase.GetById(20);
}
public static ActionResult Action2((IRatingDatabase RatingDatabase, ICommentsDatabase CommentsDatabase) d) {
var ratings = d.RatingDatabase.GetById(20);
var comments = d.CommentsDatabase.GetById(20);
}
}
答案 0 :(得分:0)
正如 @ haim770 建议的那样,您必须在Dependencies
类中创建一个期望所有依赖项的构造函数。
但在这种情况下,您只需将问题从控制器移到Dependencies类。
// Dependencies of Controller
class Dependencies {
public IUserDatabase UserDatabase { get; set; }
public IProductDatabase ProductDatabase { get; set; }
// more dependencies ...
public Dependencies(IUserDatabase userDatabase, IProductDatabase productDatabase)
{
UserDatabase = userDatabase;
ProductDatabase = productDatabase;
}
}
然后,您的容器代码将起作用。
var container = new Container();
var dependencies = container.GetInstance<Dependencies>();
答案 1 :(得分:0)
这可以通过Setter Injection Policies实现,请参阅http://structuremap.github.io/setter-injection/。
var container = new Container(x => {
x.Policies.SetAllProperties(
policy => policy.Matching(
property => property.DeclaringType == typeof(Dependencies)
);
});
您还可以更通用的方式定义策略,并为依赖项对象使用标记接口。
interface IDependencies {}
property => typeof(IDependencies).IsAssignableFrom(property.DeclaringType)