确定泛型类型是否具有相应的实现

时间:2012-01-11 19:08:52

标签: c# generics

我有一系列静态方法来修改集合,然后返回修改后的集合:

private static IEnumerable<Invoice> ResolveProxies(IEnumerable<Invoice> e) {
    // do something to e
    return e;
}

private static IEnumerable<Person> ResolveProxies(IEnumerable<Person> e) {
    // do something to e
    return e;
}

在应用程序的另一部分中,有一种方法可以确定某个集合是否属于某种类型,以便可以将其转换为该类型并使其具有相应的ResolveProxies方法:

public static GridModel<T> ToGridModel<T>(this GridModel gridModel) {
    // gridModel.Data is just IEnumerable
    var collection = gridModel.Data as IEnumerable<T> ?? new List<T>();

    return new GridModel<T> {
        Data = EvaluateDynamicProxies(collection),
        Total = gridModel.Total
    };
}

private static IEnumerable<T> EvaluateProxies<T>(IEnumerable<T> collection) {
    if (collection is IEnumerable<Invoice>) {
        var enumeration = (collection as IEnumerable<Invoice>);
        return ResolveProxies(enumeration) as IEnumerable<T>;
    }
    if (collection is IEnumerable<Person>) {
        var enumeration = (collection as IEnumerable<Person>);
        return ResolveProxies(enumeration) as IEnumerable<T>;
    }

    // proxy resolution isn't needed so return the unchanged collection
    return collection;
}

具有这种重复的条件逻辑是不好的代码味道。我正在努力想出一些标记特定类型的方法,以便我知道他们有相应的代理解析器方法。也许是这样的事情:

public interface IProxyResolver<out T> where T:IEnumerable<T> {
    T ResolveProxies();
}

但我怎么用呢?实际上我需要一种方法来询问编译器:

  1. T是否有匹配的ResolveProxies方法?
  2. 解析T代理的类或方法的名称是什么,以便我可以获取它的实例并调用它?

2 个答案:

答案 0 :(得分:1)

如何使用自定义属性?这是选择自定义序列化程序的方式等。

首先定义Attribute类:

public class ProxyResolverAttribute : Attribute {
    public Type ResolverType { get; set; }
    public ProxyResolver(Type resolverType) { ResolverType = resolverType; }
}

然后将其放在包含的类型上,例如

[ProxyResolver(TypeOf(InvoiceProxyResolver))]
public class Invoice ... { ... }

然后使用反射来查看集合中使用的泛型类型是否指定了代理解析器类型:

// Untested, beware of bugs
var enumerationGenericType = enumeration.GetType().GetGenericArguments().FirstOrDefault();
var resolverAttribute = enumerationGenericType.GetType().GetCustomAttributes(TypeOf(ProxyResolverAttribute)).FirstOrDefault();

if (resolverAttribute != null) {
    var resolverType = resolverAttribute.ResolverType;
    // instanciate something of resolverType here
}

编辑:阅读评论,如果你不想将属性应用于包含的对象,我建议创建继承List并在那里应用属性的自定义类,例如。

[ProxyResolver(TypeOf(InvoiceProxyResolver))]
public class InvoiceList : List<Invoice>   

答案 1 :(得分:1)

您可以使用控制反转(IOC)框架。例如,我的团队使用Castle Windsor。您可以注册提供服务的服务(通常是接口)和类型。它有一些很好的泛型分辨率,所以你可以做这样的事情:

interface IProxyResolver<T> { /* whatever */ }
class ProxyResolver<T> : IProxyResolver<T> { /* ... */ }
class PersonProxyResolver : ProxyResolver<Person> { }
class InvoiceProxyResolver : ProxyResolver<Invoice> { }

然后,您可以召唤这些类型:

void SomeMethodThatNeedsAProxyResolver<T>(T obj)
{
    var resolver = ioc.Resolve<IProxyResolver<T>>();
    //...
}

如果您已注册上述类,当T为PersonInvoice时,您将获得ProxyResolver的正确非泛型子类;如果是任何其他类型,则获得默认的通用超类。当然,你可以用不同的方式构建东西;如果您需要针对每种类型的特定代理解析器,那也是可能的。