将匿名类型转换为类

36

我在 List<T>里获得了一个匿名类型的实例。

var anBook=new []{

new {Code=10, Book ="Harry Potter"},
new {Code=11, Book="James Bond"}
};

以下是 clearBook 定义,是否可能将其转换为 List:

public class ClearBook
{
  int Code;
  string Book; 
}
通过直接转换,即不通过循环遍历anBook,您可以实现什么?
4个回答

54

好的,您可以使用:

var list = anBook.Select(x => new ClearBook {
               Code = x.Code, Book = x.Book}).ToList();

但是,没有直接的转换支持。很明显你需要添加访问器等(不要将字段设为公共)。我猜测:

public int Code { get; set; }
public string Book { get; set; }

当然,另一种选择是从你想要的数据开始:

var list = new List<ClearBook> {
    new ClearBook { Code=10, Book="Harry Potter" },
    new ClearBook { Code=11, Book="James Bond" }
};

你也可以使用反射来映射数据(例如使用Expression编译和缓存策略),但这可能不值得。


13

如Marc所说,可以使用反射和表达式树来完成... 幸运的是,在MiscUtil中有一个类恰好可以做到这一点。但是,仔细查看您的问题后,似乎您想要将此转换应用于集合(数组、列表或其他)而不使用循环,这是不可能的。您正在从一种类型转换为另一种类型 - 没有像引用ClearBook一样使用匿名类型的引用。

然而,为了说明PropertyCopy类的工作原理,您只需要:

var books = anBook.Select(book => PropertyCopy<ClearBook>.CopyFrom(book))
                                 .ToList();

CLR不能推断类型和属性名称并进行自动转换吗?.Net 4.0应该在这方面有所改进。 - Graviton
这样我就不必自己声明类型了。 - Graviton
我不能说我见过很多这方面的需求,而且总体上感觉这是个不好的想法。 - Jon Skeet
在 MVC 控制器中使用它进行 JsonResult 的集成测试 - SkeetJon

9
这些扩展怎么样?只需在匿名类型上简单调用.ToNonAnonymousList即可。
public static object ToNonAnonymousList<T>(this List<T> list, Type t)
    {
        //define system Type representing List of objects of T type:
        Type genericType = typeof (List<>).MakeGenericType(t);

        //create an object instance of defined type:
        object l = Activator.CreateInstance(genericType);

        //get method Add from from the list:
        MethodInfo addMethod = l.GetType().GetMethod("Add");

        //loop through the calling list:
        foreach (T item in list)
        {
            //convert each object of the list into T object by calling extension ToType<T>()
            //Add this object to newly created list:
            addMethod.Invoke(l, new[] {item.ToType(t)});
        }
        //return List of T objects:
        return l;
    }
    public static object ToType<T>(this object obj, T type)
    {
        //create instance of T type object:
        object tmp = Activator.CreateInstance(Type.GetType(type.ToString()));

        //loop through the properties of the object you want to covert:          
        foreach (PropertyInfo pi in obj.GetType().GetProperties())
        {
            try
            {
                //get the value of property and try to assign it to the property of T type object:
                tmp.GetType().GetProperty(pi.Name).SetValue(tmp, pi.GetValue(obj, null), null);
            }
            catch (Exception ex)
            {
                Logging.Log.Error(ex);
            }
        }
        //return the T type object:         
        return tmp;
    }

在你的 ToType<T>() 中,你需要执行以下操作: var value = GetProperty(obj.GetType(), pi.Name).GetValue(obj, null);GetProperty(typeof(T), pi.Name).SetValue(tmp, value, null); (否则你试图在 obj 上使用 tmp 的 getter,这是行不通的) - Philip Atz

4

最简单的方法可能就是使用某种类型的序列化方法。

类似于以下这些内容

class ClearBook
{
   public int Code { get; set; }
   public string Book { get; set; }
}

ClearBook[] newList = JsonSerializer.Deserialize<ClearBook[]>(JsonSerializer.Serialize(anBook));

2
这里有一个 List<ClearBook> 吗? - Serge

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接