注释供应商链的最佳方式

发布于 2024-07-16 01:49:42 字数 1196 浏览 3 评论 0原文

媒体浏览器有一个提供者模型,这基本上是一个类链,每个实体按特定顺序调用。

例如,我们有:

        providers = new List<IMetadataProvider>();
        providers.Add(new ImageFromMediaLocationProvider());
        providers.Add(new ImageByNameProvider());
        providers.Add(new MovieProviderFromXml());
        providers.Add(new MovieDbProvider());
        providers.Add(new TVProviderFromXmlFiles());
        providers.Add(new TvDbProvider());
        providers.Add(new VirtualFolderProvider());
        providers.Add(new FrameGrabProvider());
        providers.Add(new MediaInfoProvider());

列表中提供者的顺序重要较高顺序的提供者优先于较低顺序的提供者。

最近,我尝试使这部分可扩展。 因此,第三方 DLL 可以定义自己的提供程序,并将其注入到我们的链中。

问题是,一旦允许第三方将自己注入链中,您就失去了定义此顺序的中心位置。

我目前有点不舒服的解决方案是为每个提供者定义一个可选的优先级属性,然后按优先级排序。

例如,我现在有:

[ProviderPriority(20)]
class ImageByNameProvider{}

这允许第三方定义他们在链中的位置。

我想到的另一个解决方案是属性之前和之后,例如。

[Before(typeof(ImageByNameProvider))]
class ImageFromMediaLocationProvider {} 

但是,我不确定这是否更容易或更难编程。

这个问题还有其他解决方案吗? 您会选择哪种解决方案?

也许,我应该保留核心提供商的列表,并添加第三方提供商的之前/之后属性......

Media Browser has a provider model, this is basically a chain of classes that get called in a particular order for each entity.

So for example we have:

        providers = new List<IMetadataProvider>();
        providers.Add(new ImageFromMediaLocationProvider());
        providers.Add(new ImageByNameProvider());
        providers.Add(new MovieProviderFromXml());
        providers.Add(new MovieDbProvider());
        providers.Add(new TVProviderFromXmlFiles());
        providers.Add(new TvDbProvider());
        providers.Add(new VirtualFolderProvider());
        providers.Add(new FrameGrabProvider());
        providers.Add(new MediaInfoProvider());

The order of the providers in the list is significant higher order providers take precedence over lower order ones.

Recently, I have tried to make this portion extensible. So a third party DLL can define its own providers that will get injected in our chain.

The problem is that once you allow for 3rd parties to inject themselves in the chain you lose a central place to define this order.

My current solution that I am a little uncomfortable with is to define a optional priority attribute with each provider and then order by the priority.

So for example I now have:

[ProviderPriority(20)]
class ImageByNameProvider{}

This allows 3rd parties to define their position in the chain.

Another solutions I thought about were before and after attribute Eg.

[Before(typeof(ImageByNameProvider))]
class ImageFromMediaLocationProvider {} 

But, I am not sure if this is easier or harder to program against.

Are there any other solutions to this problem? Which solution would you go with?

Perhaps, I should just keep the list for the core providers and add the Before/After attribs for third party providers ...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

我不在是我 2024-07-23 01:49:42

看来这里实际上有一些不同的问题需要解决。 根本问题是试图提出一种机制,允许将任意对象插入到现有列表中间的某个位置。

您没有描述 IMetadataProvider 接口实际上是什么样子,但它应该有某种方法来唯一标识提供程序(最好的选择是使用 Guid)。 使用类名的好处是,它允许您在重构等过程中根据需要重命名类,只要保持 Guid 相同,就不会影响自定义(第 3 方)提供程序。

您可能应该派生自己的列表,而不是使用简单的列表:

class ProviderList : List<IMetadataProvider { }

它公开了一种自定义(第 3 方)提供程序从该列表安装/卸载自身的方法。 这些机制需要足够聪明,知道如何将新的提供者插入到链的中间,而且还需要足够聪明,知道如何处理已插入的多个自定义提供者。 同样,删除过程也需要聪明,以处理类似的问题,并确保有人不会尝试删除您的“核心”提供商之一。

这里一个好的方法可能是将要插入的提供者的 Guid 作为参数传递给 Install() 方法。 Remove() 方法同样会获取要删除的提供者的 Guid。

例如,假设我在 MovieProviderFromXml 之后插入一个新的提供程序。 然后另一个第 3 方也会在 MovieProviderFromXml 之后安装一个新的提供程序。 新的连锁秩序应该是什么? 第二个提供程序是否始终在 MovieProviderFromXml 之后立即插入,还是从那里开始,然后跳过任何自定义提供程序并在安装的最后一个自定义提供程序之后插入(因此就在下一个“核心”提供程序之前?与该

问题相关的是您需要的想法有某种方法可以区分“核心”提供程序和自定义提供程序

最后,您需要确保有一种方法可以处理链中的故障,特别是当自定义提供程序插入到错误的位置时

。始终维护默认链的基本(“主”)列表当在该链的中间安装新的提供者时,应该创建一个新的链,但您不想丢失基本链。 将链重置回默认状态的能力

是有问题的,因为您必须确定如何处理优先级冲突,就之前/之后属性集而言,您是否允许两者在同一提供者上? 可能不是,因此创建一个具有 ChainInsert 枚举属性的 ProviderChainAttribute 可能更有意义,其中 ChainInsert 将 Before 和 After 定义为枚举值。 这允许您强制自定义提供程序决定是在指定提供程序之前还是安装。 我仍然会使用 Guid 而不是类型。

希望这能为您提供有关如何解决此问题的其他想法。

It seems like there are actually a few different issues here that should be addressed. The fundamental problem is trying to come up with a mechanism that allows an arbitrary object to be inserted in to an existing list at some point in the middle of that list.

You don't describe what the IMetadataProvider interface actually looks like, but it should have some way to uniquely identify a provider (best option would be to use a Guid). The benefit over using the class name is that it allows you to rename the classes as needed during refactoring, etc. without affecting custom (3rd party) providers as long as you keep the Guid the same.

Rather than using a simple List you should probably derive your own list:

class ProviderList : List<IMetadataProvider { }

which exposes a way for a custom (3rd party) provider to install/deinstall itself from that list. These mechanisms need to be smart enough to know how to insert the new provider in to the middle of the chain but also smart enough to know how to handle multiple custom providers which have been inserted. Likewise, the removal process needs to be smart as well to deal with similar concerns and also ensure that someone doesn't try to remove one of your "core" providers.

A good approach here would probably be to pass the Guid of the provider you want to be inserted after as a parameter to the Install() method. The Remove() method would likewise take the Guid of the provider to be removed.

For example, say I insert a new provider after MovieProviderFromXml. Then another 3rd party also installs a new provider after MovieProviderFromXml. What should the new chain order be? Does the second provider always insert immediately after MovieProviderFromXml or does it start there and then skip past any custom providers and insert after the last custom provider installed (so just before the next "core" provider?

Related to that question is the idea that you need to have some way to distinguish between your "core" providers and a custom provider.

Finally, you need to make sure there is a way to handle failures in the chain, particularly when a custom provider is inserted in the wrong location.

You do want to always maintain a base ("master") list of your default chain. When a new provider is installed in the middle of that chain, a new chain should be created but you don't want to loose the base chain. This gives you the ability to reset the chain back to the default state.

Chaining based on priority is problematic in that you then have to determine how to handle priority collisions. As far as a Before/After attribute set, would you allow both on the same provider? Probably not, so it might make more sense to create a ProviderChainAttribute that has a ChainInsert enum property, where ChainInsert defines Before and After as enum values. This allows you to force the custom provider to make a decision as to whether it installs before or after the specified provider. I would still use a Guid rather than the type.

Hopefully this gives you some other ideas on how to approach this problem.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文