【问题标题】:How to resolve classes dynamically如何动态解析类
【发布时间】:2012-10-05 05:12:36
【问题描述】:

我必须为客户生成账单,但根据他们居住的地方,账单包含几乎相同的数据,但它们的格式却大不相同。我想了几种方法来处理这个问题,例如:

public void GenerateBill(User user)
{
if(user.Location == "blah blah")
{
  //Code specific to this location
}
else if (user.Location == "dah dah")
{
  //Code specific to this location
}
}

上面的方法看起来会很长,尤其是当不同位置的新用户不断出现时。我想过做类似的事情:

public void GenerateBillForUserInBlah();

public void GenerateBilForUserInDah();

但上述情况似乎也会失控,成为维护的噩梦。

我的另一个想法是使用IGenerateBill 之类的接口,然后执行以下操作:

class UserInBlah : IGenerateBill
{
//Implement IGenerateBill members

}

但在上面,我必须为每个用户创建一个类。我可能仍然需要执行上述操作,但我认为如果 Managed Extension Framework 在这里有用的话。有替代解决方案吗?主要问题是直到运行时我才知道用户的位置,所以我必须在运行时根据用户的位置调用正确的方法。

【问题讨论】:

  • 格式有何不同?您能否将更改范围缩小到类别,然后根据客户的位置进行混搭?
  • 格式非常不同。除此之外,一些取决于位置的账单包含或多或少的数据。
  • 嗯。老实说,除非您有意尝试学习新技术或其他东西,否则 if 语句(或开关)的第一件事似乎是一个非常现实且易于实施的解决方案。我真的不认为它会很难维护或添加。
  • 我不认为维护是一场噩梦,你可以通过使用字典来避免 if else 子句,我会参考选项 1
  • @CuongLe - 我刚刚提到了 2 个用户,但是如果你要处理 60 个位置,例如,你必须为每个位置维护一个 if 或 switch 案例,或者在你的案例中,你提到了字典,你会怎么做?

标签: c# design-patterns .net-4.0 mef


【解决方案1】:

当然,这种方法:

public interface IGenerateBill {}

比其他的更优雅和可扩展。是的,MEF 可以在这里为您提供帮助。
MEF 有一个“部分元数据”的概念。如果你不熟悉它,你可以阅读它here

从概念上讲,MEF 元数据允许您编写 IGenerateBill 实现,例如包含国家代码或语言环境。稍后,在运行时,您可以通过以下方式检索正确的实现:

[BillGenerator("en-us")]
public class EnUsGenerateBill : IGenerateBill {}
[BillGenerator("ru-ru")]
public class RuRuGenerateBill : IGenerateBill {}
[BillGenerator("de-de")]
public class DeDeGenerateBill : IGenerateBill {}

container.GetExports<IGenerateBill, BillGeneratorMetadata>().Single(export => export.Metadata.Locale == "en-us");

【讨论】:

  • 我是 MEF 的新手,你能解释一下这段代码的作用以及 LINQ 部分吗?我的位置更像州县。
  • @Xaisoft:我已经发布了博客文章系列的链接,名为“MEF for beginner”。你读过这篇文章吗?
  • 我刚刚打开了链接。如果你只想回答一件事,为什么不把元数据放在课堂上,它会给你带来什么好处?
  • @Xaisoft:第一个原因是特定于 MEF 的。将元数据放入 MEF 导出定义允许您枚举 exports 而无需实例化由导出定义的 parts。在您的情况下,这允许您找到合适的账单生成器,而无需创建所有可用的账单生成器。第二个原因 - 这与元数据的概念相矛盾。在您的应用程序的生命周期内,特定生成器的国家代码将是相同的。对于特定生成器类的每个实例,它都是相同的。那么,它应该放在一个类中(例如作为一个属性)是为了什么?
【解决方案2】:

您可以在每个类中都有一个属性来返回您的位置名称

例如:

        interface IGenerateBill
        {
            void GenerateBill();
            string SupportedCountry { get; }
        }

        class UserInUs : IGenerateBill
        {
        //Implement IGenerateBill members

            public void GenerateBill()
            {
                //generate bill
            }

            public string SupportedCountry
            {
                get { return "US"; }
            }
        }
        class UserInRussia : IGenerateBill
        {
        //Implement IGenerateBill members

            public void GenerateBill()
            {
                //generate bill
            }

            public string SupportedCountry
            {
                get { return "Russia"; }
            }
        }

客户端代码将是:

        string country = //Get from user in runtime
        var billGenerator = BillgeneratorFactory.ResolveAll().ToList().First
        (x => x.SupportedCountry == country);
        billGenerator.GenerateBill;

【讨论】:

  • 你能解释一下这段代码,尤其是客户端代码吗? ResolveAll 有什么作用?
  • 你需要创建一个工厂来解析 IGenerateBill 的所有具体实现并返回为 IEnumerable。总之,BillgeneratorFactory.ResolveAll() 应该返回 UserInRussia 和 UserInUS
  • ResolveAll 来自哪里,是来自 IOC 容器吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-11-02
  • 1970-01-01
  • 2022-07-02
  • 1970-01-01
  • 2014-05-23
  • 2021-12-18
  • 1970-01-01
相关资源
最近更新 更多