【问题标题】:How can I use Dependency Injection to either Override a method or to set a default method when no dependency is explicitly injected?当没有显式注入依赖项时,如何使用依赖注入来覆盖方法或设置默认方法?
【发布时间】:2015-06-10 21:36:35
【问题描述】:

我将首先解释我尝试这样做的原因。 我的初始层次结构:

BaseClass
   |
ControlClass
   |     \
CalltoBase  DerivedClass1
              |
            CalltoBase

两个调用路径都命中基类的特定方法 根据 CalltoBase 的来源,我需要使用 该方法的不同实现。 这是我通常会做的:

BaseClass____DerivedClass2
   |              |      
ControlClass   ControlClass2
   |    \             |    \
 call DerivedClass1  call  DerivedClass3
          call                 call

问题是这个项目正在增长,将有必要 基类中该方法的更多实现。 因此,我想做这样的事情的原因,我会 每次遇到这种情况时,我只需要创建 1 个额外的派生类而不是 3 个。

BaseClass
  |      \______
ControlClass<t> \_____           
 |    \               \
call DerivedClass1<t>  tClass
       call

注意:除调用行外的每一行都是继承 我没有权限或时间来更改 系统,这样它们就不会被继承。

我的目标是做这样的事情:

public class BaseClass{code}
public class tClass : BaseClass {code}
public class ControlClass<t> : t where t : BaseClass {code}
public class DerivedClass1<t> : ControlClass<t> where t : BaseClass {code}
//defaults
public class ControlClass : ControlClass<BaseClass> {empty}
public class DerivedClass1 : ControlClass<BaseClass> {empty}

这样的事情可能吗,还是我应该接受我被搞砸了,每次都制作所有派生类?

编辑1********************************************** 在做了更多研究之后,我认为我真正的问题是: 当没有显式注入依赖项时,如何使用依赖注入来覆盖方法或设置默认方法?

编辑2************************************************

这段代码都在公司创建并被许多项目使用的库中。它适用于使用 selenium/specflow 的 UAT。

public class BaseClass
{
   public T Control<T>(string controlName, string pageName = null) 
                      where T : class
   {
      By sel = GetSelector(controlName, pageName)
      ...
      return control as T;
   }
   private By GetSelector(string controlName, string pageName = null)
   {
      pageName = string.IsNullOrEmpty(pageName) ?
                 pageMapping[Browser.GetPage()] : pageName;
      ...
      return selector;
   }
}
public class ControlClass : BaseClass
{
   public NgElement NgControl(string controlName, string pageName)
   {
      By sel = GetSelector(controlName, pageName);
      ...
      return element;
   }
   public By GetSelector(string controlName, string pageName)
   {
      pageName = string.IsNullOrEmpty(pageName) ? PageName : pageName;
      pageName = string.IsNullOrEmpty(pageName) ?
                            pageMapping[Browser.GetPage()] : pageName;
      ...
      return selector;
   }
   public string PageName
   {
      get
      {
         ...
         return returnPage.Value;
      }
   }
}
public class DerivedClass1 : ControlClass
{
   //SpecFlow GWT's
   GivenAngularClicks(string controlName)
   {
      WaitForAngular();
      NgControl(crontrolName).Click();
   }
}

改变pageName的部分是根据调用者是哪个项目需要修改的部分。调用哪个派生类并不重要,重要的是实例化基类的类。

【问题讨论】:

  • 你为什么要这样做?你为什么要注入一种方法?您能否详细说明这里的场景,使其更具体,也许存在完全不同的解决方案?
  • 要遵循您的目标真的很难。一个显示谁在调用什么的最小代码示例,带有多余的参数并删除了您的其余代码,这可能更容易理解。目前尚不清楚为什么不能将基本方法声明为虚拟方法并在层次结构中适当地覆盖它。

标签: c# generics inheritance dependency-injection


【解决方案1】:

我认为在你的情况下最好制作更复杂的基类 - 你的层次结构看起来像用于提供一些帮助和辅助功能的继承。将其水平拆分为服务并进行聚合而不是制作难以理解的混合通用层次结构可能会更好?

你可能只使用类中的 .ctors 来初始化并且可以将其更改为工厂吗?

为什么你这么肯定你必须有拆分然后合并的层次结构?

糟糕的设计会导致糟糕的问题。你可以用继承和泛型做任何事情,但是如果你必须这样做的话最好考虑一下......

【讨论】:

  • 这是一项工作,这些是许多项目使用的通用部分,因此我需要确保我所做的任何更改都不会影响这些。不幸的是,这意味着结构大修是不可能的,坚持糟糕的设计。基类实际上是一个工厂,但需要更改的部分是它如何决定返回什么,而不是它返回的东西。
  • 在旁注中,这是相对容易理解的情况还是我应该改变我的提问方式?
【解决方案2】:

难道不应该通过使用覆盖来实现这样的事情,在覆盖中你在基类上调用不同的方法?比如:

public class BaseClass
{
    public virtual void FunctionA() { ... }
    public void FunctionAVariant1() { ... }
    public void FunctionAVariant2() { ... }
}

public class DerivedClass1 : BaseClass
{
    public override void FunctionA()
    {
        base.FunctionAVariant1();
    }
}

public class DerivedClass2 : BaseClass
{
    public override void FunctionA()
    {
        base.FunctionAVariant2();
    }
}

【讨论】:

  • 我不想这样做的原因是,在当前设置下,我需要为遇到的每个更改创建 3 个派生类。如果我可以在设置期间在附近,我会设置它以利用它,但无论何时设置,他们都没有预见到这个问题。
【解决方案3】:

也许你可以检查一下你在基类中是什么类型。

public class BaseClass
{
    public void Call()
    {
        if (this is DerivedClass<int>)
        {
            CallInt();
        }
        else if (this is DerivedClass<string>)
        {
            CallString();
        }
        else
        {
            Console.WriteLine("Base class");
        }
    }

    public void CallInt()
    {
        Console.WriteLine("It's an int");
    }

    public void CallString()
    {
        Console.WriteLine("It's a string");
    }
}

public class DerivedClass<T> : BaseClass {

}

public class Program
{
    public static void Main()
    {
        var intClass = new DerivedClass<int>();
        var stringClass = new DerivedClass<string>();
        intClass.Call(); // writes 'It's an int'
        stringClass.Call(); // writes 'It's a string'
    }
}

【讨论】:

    猜你喜欢
    • 2011-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-21
    相关资源
    最近更新 更多