How do we check whether a dynamic clay object has

2019-07-23 14:15发布

I have a dynamic object, that I think is implemented with Clay. It has one of two possible property names. I want to use which ever property name is available. The following doesn't work:

dynamic workItemPart = item.WorkItem; // is an Orchard.ContentManagement.ContentPart
var learnMore = workItemPart.LearnMore ?? workItemPart.LearnMoreField;

It throws a Microsoft.CSharp.RuntimeBinder.RuntimeBinderException:

does not contain a definition for 'LearnMore'

How do we check if a dynamic Clay object has a property? In JavaScript, for instance, we can do the following.

var workItemPart = {
    LearnMoreField: "Sure"    
    }
console.log(workItemPart.LearnMore || workItemPart.LearnMoreField);

Is there anything this concise in C# with Clay?

Related:

Is Orchard.ContentManagement.ContentPart implemented with Clay?

https://twitter.com/bleroy/status/497078654405312512

3条回答
够拽才男人
2楼-- · 2019-07-23 14:46

You can use an extension method to check if property exists:

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

Usage:

bool hasProperty = Extensions.HasProperty(workItemPart, "LearnMore");

var learnMore =  hasProperty ? workItemPart.LearnMore : workItemPart.LearnMoreField;

It doesn't look like an extension method though.. since the workItemPart is dynamic you need to call it explicitly by specifying the class name.

查看更多
地球回转人心会变
3楼-- · 2019-07-23 14:48

@Shaun Luttin, quite an old issue in the context of the Orchard cms, but recently I've proposed this pull request that has been committed

So, now you can use the following without throwing an exception

    if (contentItem.SomePart != null)
    if (part.SomeField != null)

The ContentItem and ContentPart classes inherit from System.Dynamic.DynamicObject and override the TryGetMember() method. And, before, if no property found the method returned false

    return false;

Now, even if the result object (the out parameter of the method) is set to null, the method return true which prevents from throwing an exception

    result = null;
    return true;

For more details, see the related PR link above

Best

查看更多
4楼-- · 2019-07-23 15:11

You can also use the indexed approach:

var learnMore = workItemPart["LearnMore"] != null ? 
     workItemPart.LearnMore : workItemPart.LearnMoreField;

Hope this helps.

UPDATE

I'm not sure why it doesn't. Both methods should work.

        dynamic New = new ClayFactory();
        var person = New.Person();
        person.skill = "Outstanding";
        var talent = person.talent;
        var talentTwo = person["talent"];
        var skill = person.talent ?? person.skill;
        Console.WriteLine(skill);
        skill = person.skill ?? person.talent;
        Console.WriteLine(skill);

Perhaps it is Orchard throwing you a curveball ...

Interesting enough, the null-coalesce operator does not process the first test case correctly. However, the standard test succeeds:

        skill = person.talent != null ? person.talent : person.skill;
        Console.WriteLine(skill);

Not sure what to advise you at this point.

查看更多
登录 后发表回答