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

本文关键字:实现 泛型类型 是否 | 更新日期: 2023-09-27 18:20:06

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

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的代理以便我可以获得它的实例并调用它的类或方法的名称是什么

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

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

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的正确的非泛型子类;如果是任何其他类型,则获得默认的泛型超类。当然,你可以用不同的方式构建事物;如果每种类型都需要一个特定的代理解析程序,这也是可能的。

使用自定义属性怎么样?这就是如何选择自定义序列化程序等。

首先定义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>