Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cast a projected list using LINQ returns a list of null values?

When I try to Cast the projected list in the BuildTypes method, I get a list of null values. I have also tried using the .Cast(), but I get an error that some of the properties cannot be cast. I can post the error if it is helpful. Here is my code:

public class AuditActionType: EntityValueType
{
}

private List<T> BuildTypes<T>(XDocument xDocument) where T: EntityValueType
{
    var types = 
        (from ty in xDocument.Descendants("RECORD")
         select new
            {
                Id = GenerateGuid(),
                Name = ty.Element("Name").Value,
                EntityStatus = _activeEntityStatus,
                DateCreated = DateTime.Now,
                DateModified = DateTime.Now
            } as T).ToList();

    return types;
} 

So I would call it like this:

var auditActorTypes = BuildTypes<AuditActorType>(auditActorTypesXml)

I have a ton of types I need to pull from an XML file and didn't want to duplicate code for each type.

like image 524
DDiVita Avatar asked Dec 17 '22 06:12

DDiVita


2 Answers

You are trying to cast an anonymous object as type T, which cannot be done. The anonymous type is it's own unique type and in no way related to the T passed in.

Instead, you could supply the new() constraint on type T to mean it needs a default constructor, and then perform a new T() instead of creating a new anonymous type:

private List<T> BuildTypes<T>(XDocument xDocument) where T: EntityValueType, new()
{
    var types = 
        (from ty in xDocument.Descendants("RECORD")
         select new T()
            {
                Id = GenerateGuid(),
                Name = ty.Element("Name").Value,
                EntityStatus = _activeEntityStatus,
                DateCreated = DateTime.Now,
                DateModified = DateTime.Now
            }).ToList();

    return types;
} 

This is assuming, of course, that Id, Name, EntityStatus, DateCreated, and DateModified are all properties of the base EntityValueType.

like image 171
James Michael Hare Avatar answered Dec 18 '22 21:12

James Michael Hare


You cannot do this with your current code as new { } creates an anonymous type which has no relationship with T (it is neither a child, nor is it of type T). What you could do instead is implement Id, Name, EntityStatus, DateCreated and DateModified as properties on your EntityValueType class and change:

private List<T> BuildTypes<T>(XDocument xDocument) where T: EntityValueType

To:

 private List<T> BuildTypes<T>(XDocument xDocument) where T: EntityValueType, new()

Which specifies that any type argument passed to our method must have a parameterless constructor which allows use to actually construct an object of type T generically by changing:

select new { ... } as T

To:

select new T { ... }

End result:

public class EntityValueType
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    // Change this to the correct type, I was unable to determine the type from your code. 
    public string EntityStatus { get; set; }
    public DateTime DateCreated { get; set; }
    public DateTime DateModified { get; set; }
}

public class AuditActionType: EntityValueType
{
}

private List<T> BuildTypes<T>(XDocument xDocument) where T: EntityValueType, new()
{
    return (from ty in xDocument.Descendants("RECORD")
        select new T
            {
                Id = GenerateGuid(),
                Name = ty.Element("Name").Value,
                EntityStatus = _activeEntityStatus,
                DateCreated = DateTime.Now,
                DateModified = DateTime.Now
            }).ToList();
} 
like image 41
Johannes Kommer Avatar answered Dec 18 '22 19:12

Johannes Kommer