简体   繁体   中英

Selecting first non null value in a model

Let's say I have a model class that looks like this:

   public class ModelTest {
        public string val1 {get;set;}
        public string val2 {get;set;}
        public string val3 {get;set;}
   }

Somewhere in my code this ModelTest gets its data. The caveat is that, only 1 of them will hold a value

   var model = new ModelTest() {val1=null, val2="value", val3=null} //Sudo code 

What I am trying to do somehow, is compare a value to whichever 1 of the 3 items can potentially have a values, so something like:

     var testCompare = "someValue"

     if (testCompare == model. ....//how can I get the NOT NULL value from ModelTest here for comparison

While your data model isn't ideal, it is possible to check each of the properties by utilizing the ||operator to compare each value. As long as your testCompare variable does not contain null, you can also omit a null check.

if (model.val1 == testCompare || 
    model.val2 == testCompare || 
    model.val3 == testCompare)
{ }

As mentioned in the comments, if you want a more succinct version, you can use the null coalescing operator, ?? , to check subsequent properties if your prior property returns null. At the end of the null coalescing chain, the first non-null property will be compared to your testCompare string. Note that you must wrap all three properties in parentheses and that this has different behavior; it only tests the first non-null property whereas the previous version tests ALL properties for a match.

if (testCompare == (model.val1 ?? model.val2 ?? model.val3))
{
}

You could probably create a method (or even property) like:

public string Val()
{
    if (val1 != null) return val1;
    if (val2 != null) return val2;
    if (val3 != null) return val3;
    return null;
}

There is probably a shorter way to write this code. Also, if two or more of the values are not null, then it will return the first one.

You could add a property to your ModelTest class that provides the first non-null value (if any) in your object:

public class ModelTest
{
    public string val1 { get; set; }
    public string val2 { get; set; }
    public string val3 { get; set; }

    public string val => val1 ?? val2 ?? val3;
}

and then check against that:

if (model.val == testCompare) { }

What about solution which contains combination of reflection and Linq,

Test Data

var model = new ModelTest() {val1=null, val2="value", val3=null} ;

Usage

var result = 
    model.GetType()
    .GetProperties()
    .FirstOrDefault(prop => prop.GetValue(model, null) != null);

Print result

Console.WriteLine(result.GetValue(model));

This is my first attempt with reflection, suggestions are most welcome

.Net fiddle


Note: This is just an alternate solution, less performant . If you are looking for elegant solution, then kindly try other solutions.

It's a very bizarre use case, but let's go with it. Here's another option for the bonfire..

public class ModelTest {
    private string _val;
    public string val1 {get => _val; set => _val ??= value;}
    public string val2 {get => _val; set => _val ??= value;}
    public string val3 {get => _val; set => _val ??= value;}
}

Whichever one of these is set to non null ends up committing that value to _val - ??= writes the right hand into the left hand only if the left hand is null, essentially like left = left?? right left = left?? right .

It doesn't matter which you use to access the value..

Note that there is only one data storage location so this approach is incapable of remembering two values, or which value was the non null. You wouldn't use this for disparate properties like name, address and social security number because it could lead to bizarre effects elsewhere. This is for a very narrow use case of "there are three properties that are essentially the same thing, they cannot be collapsed to one, and I don't know which one will be set but i can treat them equivalent for reading"

You can override the method 'Equals' of ModelTest class however you like. Example:

public class ModelTest {

    public string val1 {get;set;}
    public string val2 {get;set;}
    public string val3 {get;set;}

    public override bool Equals(object obj)
    {
        if(!typeof(string).IsInstanceOfType(obj))
            return base.Equals(obj);

        string value = obj as string;

        if (val1.Equals(value))
            return true;

        if (val2.Equals(value))
            return true;

        if (val3.Equals(value))
            return true;

        return false;
    }

}

For to use the method:

if(model.Equals("yourValue"))
...

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