C#泛型重构

C#泛型重构,c#,generics,refactoring,C#,Generics,Refactoring,我试图重构一段代码,这段代码看起来很容易重构,但事实证明很难重构。有两种方法看起来非常相似,我觉得应该进行重构:- public class MyClass { private void AddBasicData(Receiver receiver) { var aHelper = new AHelper(); var bHelper = new BHelper(); var cHelper = new CHelper();

我试图重构一段代码,这段代码看起来很容易重构,但事实证明很难重构。有两种方法看起来非常相似,我觉得应该进行重构:-

public class MyClass
{
    private void AddBasicData(Receiver receiver)
    {
        var aHelper = new AHelper();
        var bHelper = new BHelper();
        var cHelper = new CHelper();
        receiver.ObjA = aHelper.GetBasic();
        receiver.ObjB = bHelper.GetBasic();
        receiver.ObjC = cHelper.GetBasic();
    }

    private void AddExistingData(Receiver receiver)
    {
        var aHelper = new AHelper();
        var bHelper = new BHelper();
        var cHelper = new CHelper();
        receiver.ObjA = aHelper.GetExisting();
        receiver.ObjB = bHelper.GetExisting();
        receiver.ObjC = cHelper.GetExisting();
    }
}
这个类的参考代码在这里

public class AHelper : Helper<A> 
{
}

public class BHelper : Helper<B> 
{
}

public class CHelper : Helper<C> 
{
}

public class Helper<T> : IHelper<T> where T : IMyObj
{
    public T GetBasic()
    {
       ...
    }

    public T GetExisting()
    {
       ...
    } 
}

public interface IHelper<T>
{
    T GetBasic();
    T GetExisting();
}

public class A : IMyObj {}
public class B : IMyObj {}
public class C : IMyObj {}

public interface IMyObj {}

public class Receiver
{
    public A ObjA { get; set; }
    public B ObjB { get; set; }
    public C ObjC { get; set; }
}
公共类AHelper:Helper
{
}
公共类帮助者:帮助者
{
}
公共类CHelper:Helper
{
}
公共类助手:IHelper其中T:IMyObj
{
公共T GetBasic()
{
...
}
公共T GetExisting()
{
...
} 
}
公共接口IHelper
{
T GetBasic();
T GetExisting();
}
公共A类:IMyObj{}
公共B类:IMyObj{}
公共C类:IMyObj{}
公共接口IMyObj{}
公共类接收器
{
公共对象{get;set;}
公共B ObjB{get;set;}
公共C ObjC{get;set;}
}
我的第一次尝试是像这样重构

public class MyClass
{
    private void AddBasicData(Receiver receiver)
    {
        Func<Helper<IMyObj>, IMyObj> func = x => x.GetBasic();
        AddData(receiver, func);
    }

    private void AddExistingData(Receiver receiver)
    {
        Func<Helper<IMyObj>, IMyObj> func = x => x.GetExisting();
        AddData(receiver, func);
    }

    private void AddData(Receiver receiver, Func<Helper<IMyObj>, IMyObj> func)
    {
        var aHelper = new AHelper();
        var bHelper = new BHelper();
        var cHelper = new CHelper();
        receiver.ObjA = func(aHelper);
        receiver.ObjB = func(bHelper);
        receiver.ObjC = func(cHelper);
    }
}
公共类MyClass
{
私有void addBasicATA(接收方)
{
Func Func=x=>x.GetBasic();
添加数据(接收器,功能);
}
私有void AddExistingData(接收方)
{
Func Func=x=>x.GetExisting();
添加数据(接收器,功能);
}
私有void AddData(接收方,Func Func)
{
var aHelper=新的aHelper();
var bHelper=新bHelper();
var cHelper=新cHelper();
receiver.ObjA=func(aHelper);
receiver.ObjB=func(bHelper);
receiver.ObjC=func(cHelper);
}
}
问题是像
new AHelper()
这样的对象不能分配给
Helper
:-(

有人知道如何很好地重构它吗

提前谢谢


Russell

您可以使用强制转换来解决分配问题。如果某个助手实际返回A,我认为这是可行的

private void AddData(Receiver receiver, Func<Helper<IMyObj>, IMyObj> func)
    {
        var aHelper = new AHelper();
        var bHelper = new BHelper();
        var cHelper = new CHelper();
        receiver.ObjA = (A) func(aHelper);
        receiver.ObjB = (B) func(bHelper);
        receiver.ObjC = (C) func(cHelper);
    }
private void AddData(接收方,Func-Func)
{
var aHelper=新的aHelper();
var bHelper=新bHelper();
var cHelper=新cHelper();
receiver.ObjA=(A)func(aHelper);
receiver.ObjB=(B)func(bHelper);
receiver.ObjC=(C)func(cHelper);
}
如果重写方法,则可以执行强制转换,无需更改“Func,IMyObj>的定义

公共类AHelper:Helper
{
公共重写一个GetBasic()
{
返回新的A();
}
}

尝试使用模板函数。它应该根据您传递的参数类型推断类型,因此您不需要在AddData调用中显式指定类型

public class MyClass
{

  private void AddData<T>(Receiver receiver, Func<Helper<T>, T> func)
  {
     var aHelper = new AHelper();
     var bHelper = new BHelper();
     var cHelper = new CHelper();
     receiver.ObjA = func(aHelper);
     receiver.ObjB = func(bHelper);
     receiver.ObjC = func(cHelper);
  }
}
公共类MyClass
{
私有void AddData(接收方,Func Func)
{
var aHelper=新的aHelper();
var bHelper=新bHelper();
var cHelper=新cHelper();
receiver.ObjA=func(aHelper);
receiver.ObjB=func(bHelper);
receiver.ObjC=func(cHelper);
}
}
尝试#2: 棘手的问题 我想你需要一个更通用的IHelper接口。需要这个帮助吗

public interface IHelper
{
   IMyObj GetBasic();
   IMyObj GetExisting();
}

public interface IHelper<T> : IHelper
{
   T GetBasic();
   T GetExisting();
}
公共接口IHelper
{
IMyObj GetBasic();
IMyObj GetExisting();
}
公共接口IHelper:IHelper
{
T GetBasic();
T GetExisting();
}
您必须解决派生接口和基接口之间的名称冲突,但我不确定您到底想怎么做,我的时间不多了,所以暂时不谈这个问题

尝试#3(我决心得到这个!):这会是作弊吗

  public enum RetrievalMethod
  {
     Basic,
     Existing
  }
  public class Helper<T> : IHelper<T> where T : IMyObj
  {

     public T Get(RetrievalMethod rm)
     {
        switch(rm)
        {
           case RetrievalMethod.Basic:
              return GetBasic();
           case RetrievalMethod.Existing:
              return GetExisting();
        }
     }
...
  }
...
     private void AddData(Receiver receiver, RetrievalMethod rm)
     {
        var aHelper = new AHelper();
        var bHelper = new BHelper();
        var cHelper = new CHelper();
        receiver.ObjA = aHelper.Get(rm);
        receiver.ObjB = bHelper.Get(rm);
        receiver.ObjC = cHelper.Get(rm);
     }
公共枚举检索方法
{
基本的,
现有的
}
公共类助手:IHelper其中T:IMyObj
{
公共T获取(检索方法rm)
{
交换机(rm)
{
案例检索方法。基本:
返回GetBasic();
案例检索方法。现有:
返回GetExisting();
}
}
...
}
...
私有void AddData(接收方,检索方法rm)
{
var aHelper=新的aHelper();
var bHelper=新bHelper();
var cHelper=新cHelper();
receiver.ObjA=aHelper.Get(rm);
receiver.ObjB=bHelper.Get(rm);
receiver.ObjC=cHelper.Get(rm);
}
这个怎么样

private static T GetData<T, THelper>(Func<THelper, T> func) 
    where THelper : Helper<T>, new() 
    where T : IMyObj
{ return func(new THelper()); }

private static T GetBasicData<T, THelper>() 
    where THelper : Helper<T>, new() 
    where T : IMyObj
{ return GetData(x => x.GetBasic()); }

private static T GetExistingData<T, THelper>() 
    where THelper : Helper<T>, new() 
    where T : IMyObj
{ return GetData(x => x.GetExisting()); }

private void AddBasicData(Receiver receiver)
{
    receiver.ObjA = GetBasicData<A, AHelper>();
    receiver.ObjB = GetBasicData<B, BHelper>();
    receiver.ObjC = GetBasicData<C, CHelper>();
}

private void AddExistingData(Receiver receiver)
{
    receiver.ObjA = GetExistingData<A, AHelper>();
    receiver.ObjB = GetExistingData<B, BHelper>();
    receiver.ObjC = GetExistingData<C, CHelper>();
}
private static T GetData(Func Func)
其中:Helper,new()
其中T:IMyObj
{return func(new THelper());}
私有静态T GetBasicData()
其中:Helper,new()
其中T:IMyObj
{返回GetData(x=>x.GetBasic());}
私有静态T GetExistingData()
其中:Helper,new()
其中T:IMyObj
{return GetData(x=>x.GetExisting());}
私有void addBasicATA(接收方)
{
receiver.ObjA=GetBasicData();
receiver.ObjB=GetBasicData();
receiver.ObjC=GetBasicData();
}
私有void AddExistingData(接收方)
{
receiver.ObjA=GetExistingData();
receiver.ObjB=GetExistingData();
receiver.ObjC=GetExistingData();
}

如果没有.NET 4.0中提供的协方差/反方差支持,这里没什么可做的。我已经围绕这个问题转了10分钟,我想我得到了相同的结论。func不能接受aHelper,因为func接受Helper,而aHelper是Helper。分配返回值没有问题。我的意思是,如果覆盖aHelper中的方法返回A,由于函数定义,它看起来像IMyobj,但实际上是它的类型A。因此,您可以将其强制转换并分配给receiveryes的ObjA属性。当然,返回值IMyobj可以在运行时转换为A,因为A实现了IMyobj-这不是一个实际问题。实际问题是将Helper转换为HelperOh wait,这不会起作用,因为必须是A、B和C,对吗?我认为在这种情况下,用“IMyObj”替换所有的“T”是实现重构的唯一方法。这意味着会失去一些类型含义,而在这种情况下,我认为这样做的好处不值得这么做。感谢您花时间和精力考虑这个问题。:-)是的,这可能是作弊,但这两个选项与.NET3.5最接近,我想是的,所以我把它标记为
private static T GetData<T, THelper>(Func<THelper, T> func) 
    where THelper : Helper<T>, new() 
    where T : IMyObj
{ return func(new THelper()); }

private static T GetBasicData<T, THelper>() 
    where THelper : Helper<T>, new() 
    where T : IMyObj
{ return GetData(x => x.GetBasic()); }

private static T GetExistingData<T, THelper>() 
    where THelper : Helper<T>, new() 
    where T : IMyObj
{ return GetData(x => x.GetExisting()); }

private void AddBasicData(Receiver receiver)
{
    receiver.ObjA = GetBasicData<A, AHelper>();
    receiver.ObjB = GetBasicData<B, BHelper>();
    receiver.ObjC = GetBasicData<C, CHelper>();
}

private void AddExistingData(Receiver receiver)
{
    receiver.ObjA = GetExistingData<A, AHelper>();
    receiver.ObjB = GetExistingData<B, BHelper>();
    receiver.ObjC = GetExistingData<C, CHelper>();
}