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>();
}