C# 如何自动注入所有子对象
考虑一下这个抽象类C# 如何自动注入所有子对象,c#,asp.net,inversion-of-control,ioc-container,spring.net,C#,Asp.net,Inversion Of Control,Ioc Container,Spring.net,考虑一下这个抽象类 public abstract class Foo { public Injectable Prop {get;set;} } 我有一个应用程序,我想增强它,同时进行重构以简化它。 我有100多个类调用一些相同的东西(例如ClassInjectable),我认为这种行为可以抽象并设置为基类,每个人都将继承这个基类,以便删除复制/粘贴代码 但是,我希望通过定义一个可注入的对象,然后定义一个子对象foreach以及从Foo继承的每个类,来避免在spring配置文件中复制
public abstract class Foo
{
public Injectable Prop {get;set;}
}
我有一个应用程序,我想增强它,同时进行重构以简化它。
我有100多个类调用一些相同的东西(例如ClassInjectable
),我认为这种行为可以抽象并设置为基类,每个人都将继承这个基类,以便删除复制/粘贴代码
但是,我希望通过定义一个可注入的
对象,然后定义一个子对象foreach以及从Foo
继承的每个类,来避免在spring配置文件中复制/粘贴代码
我正在寻找一种方法来设置抽象类的属性,然后设置所有子元素,以便通过配置自动获取它们。我不想让抽象类变成这样:
public abstract class Foo
{
public Injectable Prop
{
get { return (Injectable)ContextRegistry.GetContext()["Injectable"]; }
}
}
public static void Main()
{
var someUtil = (SomeUtil)ContextRegistry.GetContext()["SomeUtil"];
someUtil.DoSomething();
}
谢谢你的建议
编辑:
为了让事情更复杂一些,子类是ASP.NET页面,所以我对它们的生成方式控制有限
目前,我正在使用上面提到的代码,其中抽象类引用Id为“Injectable”的DI创建的对象。我想避免使用绳子
更新(使用解决方案)
考虑:
班级
弹簧cfg
就这样!
(不要忘记像往常一样在web.config中注册模块)
在搜索功能(也许还有优雅)时,我发现不必使用IHttpModule
(我不想再添加一个类),您可以声明BasePage
public abstract class BasePage : System.Web.UI.Page
{
public IInjectable FooProp {get;set;}
protected override OnPreInit(EventArgs e)
{
Spring.Context.Support.WebApplicationContext.Current
.ConfigureObject(this, typeof(BasePage).FullName);
base.OnPreInit(e);
}
}
它就像一个魅力,不需要任何额外的模块等
很高兴这也适用于UserControls(尽管生命周期中的事件不同,因为UserControls不存在OnPreInit):
谢谢收看 我认为您建议的是一个从配置文件中获取属性列表的类。如果这是真的,您应该查看
代码生成器
。您可以创建一个简单的代码生成器,用于读取配置文件并在给定的子类中创建属性。这应该是一个很好的开始。大多数依赖项注入框架都允许通过“约定”进行注入绑定。例如,您可以在属性上放置一个属性来标记它进行注入,当DI框架构造一个类时,它将知道向该属性中注入一个值
public abstract class Foo
{
[Inject]
public Bar Bar {get; set;}
}
public class Baz : Foo
{
...
}
public class SomeUtil
{
Baz _baz;
public SomeUtil(Baz baz)
{
_baz = baz;
}
}
在上面的示例中,如果我们可以假设SomeUtil类是通过依赖项注入生成的,那么可以将DI框架配置为生成Baz并填充其Bar属性
public abstract class Foo
{
[Inject]
public Bar Bar {get; set;}
}
public class Baz : Foo
{
...
}
public class SomeUtil
{
Baz _baz;
public SomeUtil(Baz baz)
{
_baz = baz;
}
}
我不知道Spring的具体实现,但这是我将研究的总体方向
更新
当我谈到“约定”绑定时,我指的是自动布线。托布森的回答对春天的自动布线有很好的参考价值。它似乎比我一直使用的Ninject更难。但是,通过查看这些文档,您似乎可以告诉框架自动向具有指定名称或类型的任何公共属性中注入值。在我上面的例子中,您可以告诉它应该注入任何名为“Bar”的属性。因为Foo的所有子类都包含一个名为Bar的属性,所以它们都将注入这个值。这需要对配置文件进行一次性更改,之后的一切都应该“正常工作”
然而,我得到的印象是,问题的真正根源在于您没有以正确的方式使用依赖注入。托布森也意识到了这一点。如果你说newbaz()
,这是一种反依赖注入模式。相反,您的依赖关系应该逐渐上升到代码中可能的最高点(DI书籍称之为“上下文根”),在这里,您实际上会有代码要求您所需的依赖关系。如下所示:
public abstract class Foo
{
public Injectable Prop
{
get { return (Injectable)ContextRegistry.GetContext()["Injectable"]; }
}
}
public static void Main()
{
var someUtil = (SomeUtil)ContextRegistry.GetContext()["SomeUtil"];
someUtil.DoSomething();
}
在确定如何构造SomeUtil的过程中,Spring会发现它首先需要一个Baz。它会注意到Baz上有一个Bar属性,因此它会创建一个Bar并将其注入该属性,然后将Baz传递给SomeUtil的构造函数,然后返回它刚刚创建的SomeUtil
如果您对此还不十分清楚,我强烈建议您阅读。学习识别依赖注入的模式和反模式需要一些时间和练习,但一旦您识别了,这是非常有益的。您可以使用自动连线(请参见spring.net文档中的内容)用于通过spring自动设置可注入属性,而不让类知道spring的任何信息
您编写了“我希望避免这样创建抽象类”,这是一个明智的选择,因为您不应该谈论控制容器的反转
我想知道是谁负责创建那些从Foo派生的类的实例?
我认为您应该让spring创建那些从Foo派生的Asp.Net页面类的对象。似乎spring对Asp.Net页面有广泛的支持(spring.Web.support.PageHandlerFactory、spring.Web.Services.WebServiceHandlerFactory等)-我会发布一个适合您需要的配置示例,但我还没有使用ASP.Net。因此,以下是一些链接:
public static void Main()
{
var someUtil = (SomeUtil)ContextRegistry.GetContext()["SomeUtil"];
someUtil.DoSomething();
}
if (object is MyBaseClass)
applicationContext.Configure(object, "myObjectDefinitionName");
public class MyBaseClassConfigurationModule : IHttpModule {
private System.Collections.Generic.Dictionary<Type, String> typeObjectDefinitionMap;
public void Dispose() {}
public void Init(HttpApplication context) {
context.PreRequestHandlerExecute += context_PreRequestHandlerExecute;
}
void context_PreRequestHandlerExecute(object sender, EventArgs e) {
IHttpHandler handler = ((HttpApplication )sender).Context.Handler;
foreach(Type t in typeObjectDefinitionMap.Keys) {
if (t.IsAssignableFrom(app.Context.Handler.GetType)) {
Spring.Context.Support.WebApplicationContext.Current
.ConfigureObject(handler, typeObjectDefinitionMap[t]);
}
}
}
}
<object id="BasePage" type="BasePage" abstract="true">
<property name="FooProp">
<object type="ConcreteInjectable"><property.... /></object>
</property>
</object>
<object type="somePage" parent="BasePage"/>