在泛型集合

时间:2017-01-20 19:10:39

标签: c# linq generics asp.net-web-api reflection

我有一个WebAPI方法,其中有一个IEnumerable<T>个对象,其中T的类型直到运行时才知道。所以,我需要在foreach集合上执行IEnumerable<T>。问题是我无法用特定类型替换T,因为直到运行时才知道该类型。因此,我在辅助方法中使用一些反射得到T的类型,并将其存储到变量&#34; type&#34;中。但显然,我不能使用IEnumerable<type>。它会抛出一个错误,指出变量不能用作类型。

每当某些类型的数据发生更新时,我的WebAPI方法都需要记录活动。所以,我有一个自定义的ActionFilter属性设置来执行脏工作。

这是我的WebAPI方法(这只是一个虚拟测试方法):

[HttpPost]
[Route("testlogging")]
[PhiLog]
public IEnumerable<Person> UpdateTestData(Person person)
{
    IList<Person> persons = new List<Person>();
    persons.Add( person );
    persons.Add( person );
    return persons;
}

执行OnActionExecuted时,我们不知道返回给调用者的响应内容的类型。它可以只是null,或者只是一个字符串,或者只是一个int或IList<T>IEnumerable<T>,并且T的类型是未知的。这是我的自定义属性:

public class PhiLogAttribute : ActionFilterAttribute
{
    public override void OnActionExecuted( HttpActionExecutedContext actionExecutedContext )
    {
        var user = AuthenticationHelper.GetCurrentUserFromRequest( actionExecutedContext.Request );
        var actionDescriptor = actionExecutedContext.Request.GetActionDescriptor();
        var controllerName = actionDescriptor.ControllerDescriptor.ControllerName;
        var methodName = actionDescriptor.ActionName;
        var action = string.Format( "{0}/{1}", controllerName, methodName );

        var responsePayload = actionExecutedContext.Response.Content as ObjectContent;
        var payloadType = responsePayload.ObjectType;

        /* The variable below (payloadObj) could be of any type - an int, a
           string or a generic ICollection.  The code below is just assuming
           it is of type IList<Person>.  This is for my test purpose */
        var payloadObj = responsePayload.Value;

        /* AppHelper.GetEnumerableType returns the type of the generic
           parameter T. In this case, a Person type */
        var type = AppHelper.GetEnumerableType( payloadObj.GetType());

        if ( payloadType.GetInterfaces().Any( x => x.GetType().Name == "ICollection`1") )
        {
            /* This is where I am stumped.  I need to walk this
               ICollection<T> and log some value from few properties of T.
               At runtime, payloadObj is of type object.  I need to cast it
               into the correct ICollection type */
            foreach (var x in (ICollection<type>)payloadObj)
            {
                //do something with var x here.

                /* But ICollection<type> throws an error "type is a variable
                   but used like a type" */
            }
        }
    }
}

这是我的帮助方法,用于获取类型参数T的类型。

public static Type GetEnumerableType( Type type )
{
    var interfaceTypes = type.GetInterfaces();

    foreach ( Type interfaceType in interfaceTypes )
    {
        if ( interfaceType.IsGenericType && interfaceType.Name == "ICollection`1" )
            return interfaceType.GetGenericArguments()[ 0 ];
    }
    return null;
}

我在问题所在的代码中注释了内联。有人请告诉我如何在IEnumerable<T>中使用变量代替T.感谢。

1 个答案:

答案 0 :(得分:2)

  

如何在IEnumerable<T>中使用变量代替T?

你做不到。必须在编译时知道泛型类型参数。

幸运的是,在您的特定场景中,有一个简单的替代方案。由于ICollection<T>接口继承了 - 通用IEnumerable接口,因此您只需将对象转换为IEnumerable并枚举:

// using System.Collections;

foreach (object x in (IEnumerable)payloadObj)
{
    // Access properties of x using reflection or by casting to a known type...
}