简体   繁体   中英

C#, How to pass property name from string parameter for Dynamic object

My API response will return a list of JSON objects and I need to verify the order of the list, so I write a function as follows. But I got a problem for the LINQ order by sentence, it only works when I specify the actual field, but I need pass this field name as a parameter. so something like var expectedList = jObjList.OrderBy(x => x.parameterFieldName.ToString()); please give me some suggestions, many thanks.

public void VerifyOrderBy(string jsonString, string parameterFieldName)
{
    List<dynamic> jObjList = JsonConvert.DeserializeObject<List<dynamic>>(jsonString);
    var expectedList = jObjList.OrderBy(x => x.LastName.ToString());
    Assert.IsTrue(expectedList.SequenceEqual(jObjList));
}

the JSON string looks like follows

[
    {
        "FirstName": "w3pCj",
        "LastName": "mSJOV",
        "IsDeleted": false
    },
    {
        "FirstName": "rMnH7",
        "LastName": "rMnH7",
        "IsDeleted": false
    },
    {
        "FirstName": "Jia",
        "LastName": "Yu",
        "IsDeleted": false
    }
] 

You can use the nameof() operator keyword like this:

jObjList.OrderBy(x => nameof(x.LastName));

UPDATE #1

Let's say we have a Person class:

public class Person
{
    public string FirstName { get; set; }

    public string LastName { get; set; }

    public bool IsDeleted { get; set; }
}

Let's say we have a list of people:

var people =
    JsonConvert
        .DeserializeObject<List<Person>>(
            File.ReadAllText("data.json", Encoding.UTF8)
        );

We can have a parameter that will contain the property name we want to order by:

string parameterName = nameof(Person.LastName); // or simply "LastName"

We get a reference to that property:

PropertyInfo orderByProperty =
    typeof(Person)
        .GetProperties()
        .SingleOrDefault(property => property.Name == parameterName);

Now we can order by the selected property:

var result = people.OrderBy(person => orderByProperty.GetValue(person)).ToList();

Please note:

  • Of course you should check if the orderByProperty is not null . :)
  • This will work only on in-memory objects (LINQ-to-Objects) but not on a DB set (LINQ-to-SQL, EF)

Do not forget to add the required using statement to be able to get the PropertyInfo :

using System.Reflection;

UPDATE #2

If you have such a simple json structure and you want to use dynamic objects for ordering then you can achieve it like this:

var people =
    JsonConvert
        .DeserializeObject<List<dynamic>>(
            File.ReadAllText("data.json", Encoding.UTF8)
        );

string parameterName = "LastName";

var result =
    people
        .OrderBy(person =>
        {
            var personObject = person as JObject;
            var propertyValueObject = personObject.GetValue(parameterName) as JValue;

            return propertyValueObject.Value;
        })
        .ToList();

Although it works I would prefer UPDATE #1 solution. :)

Here is an implementation with custom comparer. This allows you to pass any property name:

public class JObjComp<T> : IComparer<T>
{
    private string _field;

    public JObjComp(string field)
    {
        _field = field;
    }

    int IComparer<T>.Compare(T a, T b)
    {
        //this is bit flimsy but as we know that passed object is 
        //a dynamic, should work
        dynamic aa=(dynamic)a;
        dynamic bb=(dynamic)b;
        return string.Compare(aa[_field].ToString(), bb[_field].ToString());
    }
}

Now use our custom comparer:

List<dynamic> jObjList = JsonConvert.DeserializeObject<List<dynamic>>(jstr);
jObjList.Sort(new JObjComp<dynamic>(field));

The list is sorted insitu, so you can assert using jObjList itself.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM