Xinfeng Li
Xinfeng Li

Reputation: 77

Could not convert IEnumerable of anonymous type to IEnumerable<dynamic>?

I have an action to search people in a controller, it will return a list of anonymouse:

[UnitOfWork]
[HttpGet, Route("api/Search/People")]
public virtual IHttpActionResult GetResult(string keyword)
{
    // ...
    var result = peopleList.Select(x => new
    {
        PersonId = x.Id.Value,
        EmploymentNumber = x.EmploymentNumber,
        FirstName = x.Name.FirstName,
        LastName = x.Name.LastName,
        Email = x.Email
    });
    return Ok(result);
}

Below is the test case of the method:

[Test]
public void ShouldSearchPeople()
{
    // Mocks...
    var target = new PeopleSearchController(searchRepository, personRepository, new FakePermissionProvider());
    // Error here
    var result = (OkNegotiatedContentResult<IEnumerable<dynamic>>)target.GetResult("Ashley");
    Assert.NotNull(peopleList);
    // Other assert...
}

Then I get error as below:

System.InvalidCastException: Unable to cast object of type
'System.Web.Http.Results.OkNegotiatedContentResult`1[System.Collections.Generic.IEnumerable`1[<>f__AnonymousType1e`5[System.String,System.String,System.String,System.Guid,System.String]]]'
 to type 
'System.Web.Http.Results.OkNegotiatedContentResult`1[System.Collections.Generic.IEnumerable`1[System.Object]]'.

It seems IEnumerable with class or single anonymous are OK for such convert, but IEnumerable with anonymous does not works.

How can I do such conversion? thanks.

Upvotes: 1

Views: 2452

Answers (2)

xanatos
xanatos

Reputation: 111830

You could try with

IHttpActionResult result = target.GetResult("Ashley");
IEnumerable<dynamic> content = (IEnumerable<dynamic>)((dynamic)result).Content;

You use dynamic to use the property .Content that will return a IEnumerable<T>, and then use covariance to cast it to IEnumerable<object>/IEnumerable<dynamic> (they are equivalent at the CLR level... dynamic is a magic done by the compiler)

Note that this won't work if the T of OkNegotiatedContentResult is a value type, but in your case it is a reference type, so there aren't problems.

Upvotes: -1

user2160375
user2160375

Reputation:

You are not casting some to dynamic, but concrete parametrized type to other parametrized type. The problem your code is suffering from is called covariance and contravariance. Unfortunately, class doesn't support covariance/contravariance (class is always invariant). Possible workaround:

var result = ((dynamic)target).GetResult("Ashley");
//result is of type OkNegotiatedContentResult<...>
var content = (IEnumerable<dynamic>)result.Content;

Since IEnumerable is covariant, that cast will work.

More about covariance and contravariance on MSDN.

Upvotes: 2

Related Questions