2

I'm digging into an object which contains "values" in a string format that correspond to objects and properties nested within the object I get said values from. I.E. If my object contains a list of nested objects that contains, say.. Name, within a Contact object, then I have a "value" that might read something like "ContactInfo[0].Name".

How do I verify the property exists? I'm pretty sure that if I can figure this first part out, then I can worry about getting the value with a lot less difficulty.

I've tried using something along the lines of:

public static bool HasProperty(this object obj, string propertyName)
{
    return obj.GetType().GetProperty(propertyName) != null;
}

with the arguments "MasterInfo", "Keys[0].KeyWord" and "Keys[1].Keyword" respectively.

I've tried breaking them down by DOT notation into segements and everything else I can think of, but I can't seem to use the keywords in the method successfully. Always False.

I tried running the MasterInfo object through a routine that broke the keyword down by '.' and iterated over each portion, but no change in the result... always False.

Fresh eyes are so very welcome! I've got to be missing something simple and/or right in front of me...

// simplified object example
public class MasterInfo
{
    public int Id { get; set; }

    public List<ContactInfo> Contacts {get; set;}

    public Message MessageDetail { get; set; }

    public List<Key> Keys { get; set; }
}

public class ContactInfo
{
    public int Id { get; set; }

    public string Name { get; set; }

    public string Email { get; set; }
}

public class Message
{
    public int Id { get; set; }

    public string MessageContent { get; set; }
}

public class Key
{
    public int Id { get; set; }

    public string KeyWord { get; set; }
}



// serialized JSON of what the MasterInfo class would be populated with, easier to read than with '.' notation
{
    "Id" : 1,
    "Contacts" : [
        {
            "Id" : 1,
            "Name" : "Beavis",
            "Email" : "beavis@asd.asd"
        }
    ],
    "MessageDetail" : {
        "Id" : 23,
        "MessageContent" : "Hello, %%Contacts[0].Name%%, this was sent to you at %%Contacts[0].Email%%"
    },
    "Keys" : [
        {
            "Id" : 1,
            "KeyWord" : "Contacts[0].Name"
        },
        {
            "Id" : 2,
            "KeyWord" : "Contacts[0].Email"
        }
    ]
}



// method I'm trying to use to verify the keyword (property) exists before attempting to get it's value...
public static bool HasProperty(this object obj, string propertyName)
{
    return obj.GetType().GetProperty(propertyName) != null;
}

So far, everything turns up false when evaluated. I'm pretty sure this has to do with the fact that I'm diving into nested objects, but at this point I'm not certain of anything.

BMcKinley
  • 21
  • 2
  • Your first try isn't much of an effort, given that the strings you want to parse describe not just a sequence of properties from disparate types (reflection only tells you about one type at a time), but also includes indexing on property values (which adds a whole other layer of complexity). You need to iterate down the path string, extracting each property value one at a time. – Peter Duniho Aug 15 '19 at 04:09
  • That was what I was eluding to having already tried. I'll update with an example after some sleep (attempted recursion within the above after heavy modification and looping externally, while calling the above with each level I went down). Thanks for the feedback though! :P – BMcKinley Aug 15 '19 at 04:17
  • Since you don't need to revisit parent objects as you traverse the property path, you shouldn't need recursion. Just iteration. When you update your question, please make sure it includes an actual [mcve]. Posting the JSON is a lot less useful than posting an example that includes the code to parse the JSON, or which just creates the object graph in code directly. And of course it should include your _actual_ closest effort, not some reflection call that's guaranteed not to work. See also [ask] for info on how to present your question in a clear, answerable way. – Peter Duniho Aug 15 '19 at 04:20
  • `"ContactInfo[0].Name"` looks like [tag:jsonpath] syntax so you could serialize to JSON using [tag:json.net] and check via a [`SelectToken` JSONPath query](https://www.newtonsoft.com/json/help/html/SelectToken.htm#SelectTokenJSONPath). Actually, could you have an [XY problem](https://meta.stackexchange.com/q/66377) here where you are really trying to determine whether some JSON (a *string format that correspond to objects and properties*) contains specified properties? – dbc Aug 15 '19 at 04:52
  • @dbc Thanks for the feedback. I'm a little green as far as this goes. Once the JSON above gets deserialized into the MasterInfo object, that's how i would reference the first instance of ContactInfo in the list? As in MasterInfo.Contacts[0].Name, which should yield "Beavis"? I could be off base though. Either way, thanks for constructive feedback!! – BMcKinley Aug 15 '19 at 05:13
  • @BMcKinley - if all you need to do is to check for the presence of a nested property, why deserialize at all? You can do it directly with a [tag:jsonpath] query without ever defining a data model. – dbc Aug 15 '19 at 05:15

1 Answers1

1
    public static bool HasProperty(this object obj, params string[] properties)
    {
        return HasProperty(obj.GetType(), properties);
    }

    public static bool HasProperty(this Type type, params string[] properties)
    {
        if (properties.Length == 0) // if done properly, shouldn't need this
            return false;

        var propertyInfo = type.GetProperty(properties[0]);
        if (propertyInfo != null)
        {
            if (properties.Length == 1)
                return true;
            else // need to check the next level...
            {
                Type innerType = propertyInfo.PropertyType.GetGenericArguments().FirstOrDefault();
                if (innerType != null)
                    return HasProperty(innerType, properties.Skip(1).ToArray());
                else
                    return false;
            }
        }
        else
            return false;
    }

    public static void Testing()
    {
        MasterInfo masterInfo = new MasterInfo();
        Console.WriteLine(HasProperty(masterInfo, "Id")); // true
        Console.WriteLine(HasProperty(masterInfo, "Contacts", "Name")); // true
        Console.WriteLine(HasProperty(masterInfo, "Contacts", "Address")); // false
    }
MPost
  • 535
  • 2
  • 7
  • Thank you! I've got to sleep for real now, but I'll modify this to fit my real code and give it a whirl. I'll be back! Thanks again!!! – BMcKinley Aug 15 '19 at 05:14