【发布时间】:2017-01-20 19:10:38
【问题描述】:
我有一个 WebAPI 方法,其中有一个 IEnumerable<T> 对象,其中 T 的类型直到运行时才知道。所以,我需要在IEnumerable<T> 集合上执行foreach。问题是我无法将 T 替换为特定类型,因为该类型直到运行时才知道。因此,我使用辅助方法中的一些反射来获取 T 的类型,并将其存储到变量“类型”中。但显然,我不能使用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。谢谢。
【问题讨论】:
标签: c# linq generics asp.net-web-api reflection