如何动态定义匿名对象属性?

时间:2018-04-14 13:21:18

标签: c# asp.net-core asp.net-core-webapi

我在我的网站上制作一个小应用程序,以使用API​​请求获取用户信息。

[HttpGet("GetUserInfo/{user_id}/{fields?}")]
public IActionResult GetUserInfo(string user_id, params string[] fields)
{
    var userProfile = _userManager.GetUserProfile(user_id);

    if (userProfile == null)
    {
        return Ok(null);
    }

    var userInfo = new
    {
        id = userProfile.UserId,
        email = userProfile.Email,
        name = userProfile.Name,
        // I don't want to define a null property here:
        picture_url = fields.Contains("picture_url") ? "path" : null
    };

    if (fields.Contains("picture_url"))
    {
        userInfo.picture_url = "";
    }

    return Ok(userInfo);
}

当请求有效时,它返回一个JSON对象,默认情况下包含3个属性:idemailname

现在,我想检查一下,如果请求想要获得有关此用户的更多信息,就像picture_url一样。所以,我试过了:

if (fields.Contains("picture_url"))
{
    // error in this line
    userInfo.picture_url = "path";
}
  

'< anonymous type:string id,string email,string name>'不包含' picture_url'的定义没有扩展方法' picture_url'接受类型'<匿名类型的第一个参数:字符串id,字符串电子邮件,字符串名称>'可以找到(你错过了使用指令或程序集引用吗?)

如何动态地向匿名对象添加一些属性?

2 个答案:

答案 0 :(得分:6)

匿名类型是不可变的,您只能在创建实例时创建和设置属性。这意味着您需要创建所需的确切对象。所以你可以这样做:

if (fields.Contains("picture_url"))
{
    return Ok(new
    {
        id = userProfile.UserId,
        email = userProfile.Email,
        name = userProfile.Name,
        picture_url = "path"
    });
}

return Ok(new
{
    id = userProfile.UserId,
    email = userProfile.Email,
    name = userProfile.Name
});

另一种选择是使用Dictionary<string, object>。例如:

var userInfo = new Dictionary<string, object>
{
    {"id", userProfile.UserId},
    {"email", userProfile.Email},
    {"name", userProfile.Name}
};

if (fields.Contains("picture_url"))
{
    // error in this line
    userInfo.Add("picture_url", "path");
}

return Ok(userInfo);

此对象将序列化为相同的JSON结构:

{"id":1,"email":"email@somewhere.com","name":"Bob","picture_url":"path"}

答案 1 :(得分:0)

您可以将对象强制转换为动态并添加属性或使用ExpandoObject类,它基本上是一个属性包(实现为IDictionary<string, object>)。

var userInfo = new
{
    id = userProfile.UserId,
    email = userProfile.Email,
    name = userProfile.Name
};

dynamic result = userInfo;

if (fields.Contains("picture_url"))
{
    result.picture_url = "<your url here>";

    // alternatively use expando object
    // var expando =  (IDictionary<String, Object>)result;
    // expando.Add("picture_url", "<your url here>");
    // the first parameter is the name of the property
}

return result;

请注意,使用dynamic关键字或ExpandoObject会失去强类型和智能感知支持。

但它允许您在最终的json响应中添加或删除属性。

修改

另请参阅我对类似问题Filtering Out Properties in an ASP.NET Core API 的回答。

虽然在使用dynamic / ExandoObject作为用例或类似graphapi的功能时需要小心,但它应该可以正常工作。要删除属性,您只需使用exanod.Remove("PropertyName")方法。

也可以像

一样轻松实现过滤
var dictionaryResult = expando.Where(kv => filter.Contains(kv.Key))
    .ToDictionary(kv => kv.Key, kv => kv.Value);

这将删除filter字符串数组中未定义的所有属性。它适用于任何类型,annonymous或强类型。