【问题标题】:List of properties to anonymous Type匿名类型的属性列表
【发布时间】:2016-02-22 19:25:09
【问题描述】:

假设我有某种类型:

public class General
{
     public int Id;
     public string Name;
     public DateTime modified
}

假设我想要一些匿名功能过滤器:

public void DoWorkOnSubset(List<General> generals, params Func<general, object> properties)
{

}

如何获取属性列表并将其转换为匿名类型

generals.Select(x => new { properties.ForEach( p => p.Invoke(x)) });

【问题讨论】:

  • 所以基本上是复制类型?你想用这个来达到什么目的?
  • 匿名类型在编译时扩展为具体实现。
  • 基本上我想要一个匿名类型的子集,但直到属性传入后我才知道
  • @Scorpion 你是说我不能使用匿名类型,因为它必须在编译时建立?
  • 没有简单的方法可以做到这一点,您必须动态构建新类型。可以做到,但并不容易。使用反射获取现有类型的属性并使用TypeBuilder 动态构建类型。无论哪种方式,我都质疑您希望在这里完成什么,您将获得一个只能通过反射使用的对象。

标签: c# function lambda anonymous-function


【解决方案1】:

您不能在运行时生成新的匿名类型,因为匿名类型是实际类型,由编译器在后台生成。 .NET 用户无法通过 API 使用生成这些类型的代码,因此您必须通过 System.Reflection.Emit 调用来构建自己的代码。

下一个最接近的方法是使用动态对象,例如ExpandoObject,并使用IDictionary&lt;string,object&gt; 接口设置其值。调用者将能够使用常规语法访问此对象的字段。

编辑:如果您需要的只是一个可以在运行时访问的属性值集合,您可以使用Dictionary&lt;string,object&gt;,如下所示:

generals.Select(x =>
    properties.ToDictionary(p => p.Name, p => p.Invoke(x))
);

【讨论】:

  • 您实际上可以在运行时构建类型,请查看TypeBuilder,尽管它们几乎没有用处,因为没有代码可以直接使用这些属性。不过,您可以在新类型上实现接口,这会使其更容易,但这可能与 OP 要求的通用方法背道而驰。
  • @LasseV.Karlsen 啊,当然,如果你通过emit,你可以构建自己的类。不过,这将是一个编写简单编译器构建块的练习。
【解决方案2】:

如果有人想知道我想出了一种不用匿名类型的方法来实现这一点。我只有一个 IEnumerable 属性。

generals.Select(x => properties.Select(p => p.Invoke(x)));

我可以将其作为 IEnumerable 而不是匿名类型进行操作

【讨论】:

  • 更好的是,您可以运行ToDictionary,并将其作为字典进行操作(请参阅对我的答案的编辑以获取代码)。 IEnumerable&lt;object&gt; 的问题在于,由于延迟执行,它可能会变得非常慢,除非您将其转换为列表。
  • 感谢您的提示,我可能会切换到字典,因为这样会更容易根据键了解我正在使用的内容
【解决方案3】:

我有相同的解决方案,并通过一个简单的类和继承我的所有实体来解决这个问题:

public class Entity
{
    public Entity()
    {
        EntityPropertyDic = new Dictionary<string, object>();
    }
    public object this[string propertyName]
    {
        get
        {
            if (EntityPropertyDic.ContainsKey(propertyName))
            {
                return EntityPropertyDic[propertyName];
            }
            else
                throw new ArgumentException("PropertyName Is not exist!");
        }
        set
        {
            OnColumnChanging(propertyName, ref value);
            EntityPropertyDic[propertyName] = value;
        }
    }

    private void OnColumnChanging(string propertyName, ref object value)
    {
        throw new NotImplementedException();
    }

    protected Dictionary<string, object> EntityPropertyDic { get; set; }
}

所以你可以这样做:

public List<Entity> DoWorkOnSubset(List<General> generals, params string properties)
{
    List<Entity> entityList = new List<Entity>();
    foreach(var general in generals)
    {
        var entity = new Entity();
        foreach(var prop in properties)
        {
           entity[prop] = general[prop];
        }
        entityList.Add(entity);
    }

    return entityList;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多