泛型类型依赖注入:如何注入T

时间:2022-02-08 15:48:20

I want to handle different types of docs the same way in my application Therefore: I have a generic interface like this.

我想在我的应用程序中以相同的方式处理不同类型的文档因此:我有一个像这样的通用接口。

public interface IDocHandler<T>where T: class
{

T Document { get;set;}

void Load(T doc);

void Load(string PathToDoc);

void Execute();

void Execute(T doc);

}

And for different types of documents I implement this interface.

对于不同类型的文档,我实现了这个接口。

for example:

public class FinanceDocumentProcessor:IDocumentHandler<ReportDocument>
{} 


public class MarketingDocumentProcessor:IDocumentHandler<MediaDocument>
{} 

Then I can do of course something like this:

然后我当然可以这样做:

IDocumentHandler<ReportDocument> docProc= new FinanceDocumentProcessor();

It would be interessting to know how I could inject T at runtime to make the line above loosly coupled...

如果我知道如何在运行时注入T以使线路松散耦合,那将是非常令人兴奋的......

IDocumentHandler<ReportDocument> docProc = container.resolve("FinanceDocumentProcessor());

but I want to decide per Configuration wether I want to have my FinanceDomcumentProcessor or my MarketingDocumentProcessor... therefore I would have to inject T on the left site, too ... Since I have to use c# 2.0 I can not use the magic word "var" which would help a lot in this case... but how can I design this to be open and flexible...

但我想决定每个配置,我想要我的FinanceDomcumentProcessor或我的MarketingDocumentProcessor ...因此我也必须在左侧网站上注入T ...因为我必须使用c#2.0我不能使用魔术字“var”在这种情况下会有很大的帮助...但我怎样才能将其设计为开放灵活的......


Sorry for the misunderstanding and thanks for all the comments but I have another example for my challenge (maybe I am using the wrong design for that) ... But I give it a try: Same situation but different Explanation

很抱歉误解和感谢所有的评论,但我有另一个例子来解决我的挑战(也许我使用了错误的设计)...但是我试一试:相同的情况但不同的解释

Example Image I have:

示例图像我有:

ReportingService, Crystal, ListAndLabel Three different Reporting Document types. I have a generic Handler IReportHandler<T> (would be the same as above) this Handler provides all the functionality for handling a report Document. for Example

ReportingService,Crystal,ListAndLabel三种不同的报告文档类型。我有一个通用的Handler IReportHandler (与上面相同),这个Handler提供了处理报告文档的所有功能。例如

ChrystalReportHandler:IReportHandler<CrystalReportDocument>

Now I want to use a Framework like Unity (or some else framework) for dependency injection to decide via configuration whether I want to use Crystal, Reportingservices or List and Label.

现在我想使用像Unity(或其他框架)这样的框架来进行依赖注入,以决定是否要使用Crystal,Reportingservices或List和Label。

When I specify my mapping I can inject my ChrystalReportHandler but how can I inject T on the left side or in better word The Type of ReportDocument.

当我指定我的映射时,我可以注入我的ChrystalReportHandler,但是如何在左侧或更好的单词“ReportDocument的类型”中注入T.

IReportHandler<T (this needs also to be injected)> = IOContainer.Resolve(MyMappedType here) 

my Problem is the left Site of course because it is coupled to the type but I have my mapping ... would it be possible to generate a object based on Mapping and assign the mapped type ? or basically inject T on the left side, too? Or is this approach not suitable for this situation.

我的问题是左站点,当然因为它耦合到类型但我有我的映射...是否可以基于Mapping生成对象并分配映射类型?或者基本上也在左侧注入T?或者这种方法不适合这种情况。

3 个解决方案

#1


2  

I think that with your current design, you are creating a "dependency" between IDocumentHandler and a specific Document (ReportDocument or MediaDocument) and so if you want to use IDocumentHandler<ReportDocument or MediaDocument> directly in your code you must assume that your container will give you just that. The container shouldn't be responsible for resolving the document type in this case.

我认为,根据您当前的设计,您在IDocumentHandler和特定文档(ReportDocument或MediaDocument)之间创建了一个“依赖”,因此如果您想在代码中直接使用IDocumentHandler ,您必须假设您的容器将给你这个。在这种情况下,容器不应负责解析文档类型。 或mediadocument>

Would you consider changing your design like this?

你会考虑改变你的设计吗?

public interface IDocumentHandler
{
    IDocument Document { get; set; }

    void Load(IDocument doc);

    void Load(string PathToDoc);

    void Execute();

    void Execute(IDocument doc);

}

public class IDocument { }
public class ReportDocument : IDocument { }
public class MediaDocument : IDocument { }
public class FinanceDocumentProcessor : IDocumentHandler { }
public class MarketingDocumentProcessor : IDocumentHandler { }

#2


1  

If I understand you correctly, you have two options.

如果我理解正确,你有两种选择。

  1. if you have interface IDocHandler and multiple classes implementing it, you have to register each type explicitly, like this:

    如果您有接口IDocHandler和多个实现它的类,您必须显式注册每个类型,如下所示:

    container.AddComponent>(typeof(FooHandler));

  2. if you have one class DocHandler you can register with component using open generic type

    如果你有一个类DocHandler,你可以使用开放泛型类型注册组件

    container.AddComponent(typeof(IDocHandler<>), typeof(DocHandler<>));

then each time you resolve IDocHandler you will get an instance of DocHandler and when you resolve IDocHandler you'll get DocHandler

然后每次你解决IDocHandler,你都会得到一个DocHandler实例,当你解决IDocHandler时,你会得到DocHandler

hope that helps

希望有所帮助

#3


1  

You need to use a non-generic interface on the left side.

您需要在左侧使用非通用接口。

Try:

public interface IDocumentHandler { }
public interface IDocumentHandler<T> : IDocumentHandler { }

This will create two interfaces. Put everything common, non-T-specific into the base interface, and everything else in the generic one.

这将创建两个接口。将所有常见的,非特定于T的特性放入基本接口,以及通用的其他所有内容。

Since the code that you want to resolve an object into, that you don't know the type of processor for, you couldn't call any of the T-specific code there anyway, so you wouldn't lose anything by using the non-generic interface.

由于你想要解析一个对象的代码,你不知道处理器的类型,你无法在那里调用任何特定于T的代码,所以你不会因为使用non而丢失任何东西。 - 通用接口。


Edit: I notice my answer has been downvoted. It would be nice if people downvoting things would leave a comment why they did so. I don't care about the reputation point, that's just minor noise at this point, but if there is something seriously wrong with the answer, then I'd like to know so that I can either delete the answer (if it's way off target) or correct it.

编辑:我注意到我的答案已被低估了。如果人们贬低事情会留下评论,为什么他们这样做会很好。我不关心声望点,这点只是微小的噪音,但如果答案有严重错误,那么我想知道我可以删除答案(如果它偏离目标)或纠正它。

Now in this case I suspect that either the original questionee has downvoted it, and thus either haven't posted enough information, so that he's actually asking about something other than what he's asked about, or he didn't quite understand my answer, which is understandable since it was a bit short, or that someone who didn't understand it downvoted it, again for the same reason.

现在在这种情况下,我怀疑原来的被问者是否已经过了低估,因此他们要么没有发布足够的信息,所以他实际上询问的不是他的问题,或者他不太明白我的答案,这是可以理解的,因为它有点短,或者是那个不理解它的人,也是出于同样的原因。

Now, to elaborate.

现在,详细说明。

You can't inject anything "on the left side". That's not possible. That code have to compile, be correct, and be 100% "there" at compile-time. You can't say "we'll tell you what T is at runtime" for that part. It just isn't possible.

你不能在“左侧”注入任何东西。那是不可能的。该代码必须编译,正确,并在编译时100%“存在”。对于那部分,你不能说“我们会告诉你T在运行时是什么”。这是不可能的。

So the only thing you're left with is to remove the T altogether. Make the code that uses the dependency not depend on T, at all. Or, at the very least, use reflection to discover what T is and do things based on that knowledge.

所以你唯一留下的就是彻底删除T.使用依赖项的代码完全不依赖于T.或者,至少使用反射来发现T是什么,并根据这些知识做事。

That's all you can do. You can't make the code on the left side change itself depending on what you return from a method on the right side.

这就是你所能做的一切。根据您从右侧方法返回的内容,您无法使左侧的代码自行更改。

It isn't possible.

这是不可能的。

Hence my answer.

因此我的答案。

#1


2  

I think that with your current design, you are creating a "dependency" between IDocumentHandler and a specific Document (ReportDocument or MediaDocument) and so if you want to use IDocumentHandler<ReportDocument or MediaDocument> directly in your code you must assume that your container will give you just that. The container shouldn't be responsible for resolving the document type in this case.

我认为,根据您当前的设计,您在IDocumentHandler和特定文档(ReportDocument或MediaDocument)之间创建了一个“依赖”,因此如果您想在代码中直接使用IDocumentHandler ,您必须假设您的容器将给你这个。在这种情况下,容器不应负责解析文档类型。 或mediadocument>

Would you consider changing your design like this?

你会考虑改变你的设计吗?

public interface IDocumentHandler
{
    IDocument Document { get; set; }

    void Load(IDocument doc);

    void Load(string PathToDoc);

    void Execute();

    void Execute(IDocument doc);

}

public class IDocument { }
public class ReportDocument : IDocument { }
public class MediaDocument : IDocument { }
public class FinanceDocumentProcessor : IDocumentHandler { }
public class MarketingDocumentProcessor : IDocumentHandler { }

#2


1  

If I understand you correctly, you have two options.

如果我理解正确,你有两种选择。

  1. if you have interface IDocHandler and multiple classes implementing it, you have to register each type explicitly, like this:

    如果您有接口IDocHandler和多个实现它的类,您必须显式注册每个类型,如下所示:

    container.AddComponent>(typeof(FooHandler));

  2. if you have one class DocHandler you can register with component using open generic type

    如果你有一个类DocHandler,你可以使用开放泛型类型注册组件

    container.AddComponent(typeof(IDocHandler<>), typeof(DocHandler<>));

then each time you resolve IDocHandler you will get an instance of DocHandler and when you resolve IDocHandler you'll get DocHandler

然后每次你解决IDocHandler,你都会得到一个DocHandler实例,当你解决IDocHandler时,你会得到DocHandler

hope that helps

希望有所帮助

#3


1  

You need to use a non-generic interface on the left side.

您需要在左侧使用非通用接口。

Try:

public interface IDocumentHandler { }
public interface IDocumentHandler<T> : IDocumentHandler { }

This will create two interfaces. Put everything common, non-T-specific into the base interface, and everything else in the generic one.

这将创建两个接口。将所有常见的,非特定于T的特性放入基本接口,以及通用的其他所有内容。

Since the code that you want to resolve an object into, that you don't know the type of processor for, you couldn't call any of the T-specific code there anyway, so you wouldn't lose anything by using the non-generic interface.

由于你想要解析一个对象的代码,你不知道处理器的类型,你无法在那里调用任何特定于T的代码,所以你不会因为使用non而丢失任何东西。 - 通用接口。


Edit: I notice my answer has been downvoted. It would be nice if people downvoting things would leave a comment why they did so. I don't care about the reputation point, that's just minor noise at this point, but if there is something seriously wrong with the answer, then I'd like to know so that I can either delete the answer (if it's way off target) or correct it.

编辑:我注意到我的答案已被低估了。如果人们贬低事情会留下评论,为什么他们这样做会很好。我不关心声望点,这点只是微小的噪音,但如果答案有严重错误,那么我想知道我可以删除答案(如果它偏离目标)或纠正它。

Now in this case I suspect that either the original questionee has downvoted it, and thus either haven't posted enough information, so that he's actually asking about something other than what he's asked about, or he didn't quite understand my answer, which is understandable since it was a bit short, or that someone who didn't understand it downvoted it, again for the same reason.

现在在这种情况下,我怀疑原来的被问者是否已经过了低估,因此他们要么没有发布足够的信息,所以他实际上询问的不是他的问题,或者他不太明白我的答案,这是可以理解的,因为它有点短,或者是那个不理解它的人,也是出于同样的原因。

Now, to elaborate.

现在,详细说明。

You can't inject anything "on the left side". That's not possible. That code have to compile, be correct, and be 100% "there" at compile-time. You can't say "we'll tell you what T is at runtime" for that part. It just isn't possible.

你不能在“左侧”注入任何东西。那是不可能的。该代码必须编译,正确,并在编译时100%“存在”。对于那部分,你不能说“我们会告诉你T在运行时是什么”。这是不可能的。

So the only thing you're left with is to remove the T altogether. Make the code that uses the dependency not depend on T, at all. Or, at the very least, use reflection to discover what T is and do things based on that knowledge.

所以你唯一留下的就是彻底删除T.使用依赖项的代码完全不依赖于T.或者,至少使用反射来发现T是什么,并根据这些知识做事。

That's all you can do. You can't make the code on the left side change itself depending on what you return from a method on the right side.

这就是你所能做的一切。根据您从右侧方法返回的内容,您无法使左侧的代码自行更改。

It isn't possible.

这是不可能的。

Hence my answer.

因此我的答案。