如何使用反射重构重复代码
How to refactor repeated code using reflection
所以我有这个大的 switch 语句,它本质上是重复多次相同的代码,其中唯一改变的是强制转换为特定的 class。我一直在尝试找出一种使用反射重构它的方法,所以我只需要写一次。
switch(provider)
{
case SocialNetworks.Linkedin:
{
List<Linkedin> profiles = await MobileService.GetTable<Linkedin>().Where(p => p.uuid == (obj as Linkedin).uuid).ToListAsync();
if (profiles.Count == 0)
{
await MobileService.GetTable<Linkedin>().InsertAsync(obj as Linkedin);
}
break;
}
case SocialNetworks.Facebook:
{
List<Facebook> profiles = await MobileService.GetTable<Facebook>().Where(p => p.uuid == (obj as Facebook).uuid).ToListAsync();
if (profiles.Count == 0)
{
await MobileService.GetTable<Facebook>().InsertAsync(obj as Facebook);
}
break;
}
case SocialNetworks.Twitter:
{
List<Twitter> profiles = await MobileService.GetTable<Twitter>().Where(p => p.uuid == (obj as Twitter).uuid).ToListAsync();
if (profiles.Count == 0)
{
await MobileService.GetTable<Twitter>().InsertAsync(obj as Twitter);
}
break;
}
}
请注意,此处 obj
是 Object
类型,MobileService
是 MobileServiceClient
类型,后者是 Windows Azure 移动服务库的一部分。
您可以在不使用反射的情况下通过创建一个接受泛型类型参数的函数来解决这个问题。一个简单的例子是:
public List<T> SomeFunction<T>()
{
return new List<T>();
}
然后这样称呼它:
var list = SomeFunction<FaceBook>();
假设您的 Facebook
、Twitter
和 Linkedin
class 继承自基 class SocialNetwork
.
void FunctionX(SocialNetworks provider, object obj)
{
switch(provider)
{
case SocialNetworks.Linkedin:
{
FunctionY<Linkedin>(obj as Linkedin);
break;
}
case SocialNetworks.Facebook:
{
FunctionY<Facebook>(obj as Facebook);
break;
}
case SocialNetworks.Twitter:
{
FunctionY<Twitter>(obj as Twitter);
break;
}
}
}
void FunctionY<T>(SocialNetwork obj)
{
List<T> profiles = await MobileService.GetTable<T>().Where(p => p.uuid == (obj).uuid).ToListAsync();
if (profiles.Count == 0)
{
await MobileService.GetTable<T>().InsertAsync(obj);
}
}
回答原始问题如何通过反射以通用方式重写此方法,以便该方法不需要为每个新的社交网络进行更改。
如果要处理 MySpace,您只需将其添加到 handlerMapping,HandleAnySocialNetworkByMapping() 不变(请参阅下面的代码)。
class Program
{
private readonly static Dictionary<SocialNetworks, Type> handlerMapping = new Dictionary<SocialNetworks, Type>()
{
{SocialNetworks.Linkedin, typeof(Linkedin)},
{SocialNetworks.Facebook, typeof(Facebook)},
{SocialNetworks.Twitter, typeof(Twitter)},
};
static void Main(string[] args)
{
HandleAnySocialNetworkByMapping(SocialNetworks.Facebook, new Facebook()).Wait();
HandleAnySocialNetworkByMapping(SocialNetworks.Linkedin, new Linkedin()).Wait();
HandleAnySocialNetworkByMapping(SocialNetworks.Twitter, new Twitter()).Wait();
}
private async static Task HandleAnySocialNetworkByMapping(SocialNetworks provider, object socialNetwork)
{
Type handler = handlerMapping[provider];
var insertIfNotExistsMethodInfo = typeof(SocialRepository)
.GetMethods()
.First(m => m.Name == "InsertIfNotExists");
await (Task)insertIfNotExistsMethodInfo.MakeGenericMethod(handler).Invoke(new SocialRepository(), new[] { socialNetwork });
}
}
在哪里
SocialRepository 包含持久性逻辑
public class SocialRepository
{
public async Task InsertIfNotExists<TEntity>(TEntity obj) where TEntity : Social
{
var profile = await MobileService.GetTable<TEntity>().FirstOrDefault(p => p.uuid == obj.uuid);
if (profile == null)
{
await MobileService.GetTable<TEntity>().InsertAsync(obj);
}
}
}
实体
public abstract class Social { public Guid uuid { get; private set; } }
public class Linkedin : Social{/*...*/}
public class Twitter : Social{/*...*/}
public class Facebook : Social{/*...*/}
public enum SocialNetworks
{
Linkedin,
Facebook,
Twitter
}
所以我有这个大的 switch 语句,它本质上是重复多次相同的代码,其中唯一改变的是强制转换为特定的 class。我一直在尝试找出一种使用反射重构它的方法,所以我只需要写一次。
switch(provider)
{
case SocialNetworks.Linkedin:
{
List<Linkedin> profiles = await MobileService.GetTable<Linkedin>().Where(p => p.uuid == (obj as Linkedin).uuid).ToListAsync();
if (profiles.Count == 0)
{
await MobileService.GetTable<Linkedin>().InsertAsync(obj as Linkedin);
}
break;
}
case SocialNetworks.Facebook:
{
List<Facebook> profiles = await MobileService.GetTable<Facebook>().Where(p => p.uuid == (obj as Facebook).uuid).ToListAsync();
if (profiles.Count == 0)
{
await MobileService.GetTable<Facebook>().InsertAsync(obj as Facebook);
}
break;
}
case SocialNetworks.Twitter:
{
List<Twitter> profiles = await MobileService.GetTable<Twitter>().Where(p => p.uuid == (obj as Twitter).uuid).ToListAsync();
if (profiles.Count == 0)
{
await MobileService.GetTable<Twitter>().InsertAsync(obj as Twitter);
}
break;
}
}
请注意,此处 obj
是 Object
类型,MobileService
是 MobileServiceClient
类型,后者是 Windows Azure 移动服务库的一部分。
您可以在不使用反射的情况下通过创建一个接受泛型类型参数的函数来解决这个问题。一个简单的例子是:
public List<T> SomeFunction<T>()
{
return new List<T>();
}
然后这样称呼它:
var list = SomeFunction<FaceBook>();
假设您的 Facebook
、Twitter
和 Linkedin
class 继承自基 class SocialNetwork
.
void FunctionX(SocialNetworks provider, object obj)
{
switch(provider)
{
case SocialNetworks.Linkedin:
{
FunctionY<Linkedin>(obj as Linkedin);
break;
}
case SocialNetworks.Facebook:
{
FunctionY<Facebook>(obj as Facebook);
break;
}
case SocialNetworks.Twitter:
{
FunctionY<Twitter>(obj as Twitter);
break;
}
}
}
void FunctionY<T>(SocialNetwork obj)
{
List<T> profiles = await MobileService.GetTable<T>().Where(p => p.uuid == (obj).uuid).ToListAsync();
if (profiles.Count == 0)
{
await MobileService.GetTable<T>().InsertAsync(obj);
}
}
回答原始问题如何通过反射以通用方式重写此方法,以便该方法不需要为每个新的社交网络进行更改。
如果要处理 MySpace,您只需将其添加到 handlerMapping,HandleAnySocialNetworkByMapping() 不变(请参阅下面的代码)。
class Program
{
private readonly static Dictionary<SocialNetworks, Type> handlerMapping = new Dictionary<SocialNetworks, Type>()
{
{SocialNetworks.Linkedin, typeof(Linkedin)},
{SocialNetworks.Facebook, typeof(Facebook)},
{SocialNetworks.Twitter, typeof(Twitter)},
};
static void Main(string[] args)
{
HandleAnySocialNetworkByMapping(SocialNetworks.Facebook, new Facebook()).Wait();
HandleAnySocialNetworkByMapping(SocialNetworks.Linkedin, new Linkedin()).Wait();
HandleAnySocialNetworkByMapping(SocialNetworks.Twitter, new Twitter()).Wait();
}
private async static Task HandleAnySocialNetworkByMapping(SocialNetworks provider, object socialNetwork)
{
Type handler = handlerMapping[provider];
var insertIfNotExistsMethodInfo = typeof(SocialRepository)
.GetMethods()
.First(m => m.Name == "InsertIfNotExists");
await (Task)insertIfNotExistsMethodInfo.MakeGenericMethod(handler).Invoke(new SocialRepository(), new[] { socialNetwork });
}
}
在哪里 SocialRepository 包含持久性逻辑
public class SocialRepository
{
public async Task InsertIfNotExists<TEntity>(TEntity obj) where TEntity : Social
{
var profile = await MobileService.GetTable<TEntity>().FirstOrDefault(p => p.uuid == obj.uuid);
if (profile == null)
{
await MobileService.GetTable<TEntity>().InsertAsync(obj);
}
}
}
实体
public abstract class Social { public Guid uuid { get; private set; } }
public class Linkedin : Social{/*...*/}
public class Twitter : Social{/*...*/}
public class Facebook : Social{/*...*/}
public enum SocialNetworks
{
Linkedin,
Facebook,
Twitter
}