fdkgfosfskjdlsjdlkfsf
fdkgfosfskjdlsjdlkfsf

Reputation: 3303

Any easy way to see which IF condition is false?

I'm posting this question to find a simpler way of achieving a result.

We have a big IF statement that checks for NULL or string.empty. Something like this:

if (string.IsNullOrEmpty(Empl.Name) || string.IsNullOrEmpty(Empl.last) ||
   string.IsNullOrEmpty(Empl.init) || string.IsNullOrEmpty(Empl.cat1) ||
   string.IsNullOrEmpty(Empl.history) || string.IsNullOrEmpty(Empl.cat2) ||
   string.IsNullOrEmpty(Empl.year) || string.IsNullOrEmpty(Empl.month) || 
   string.IsNullOrEmpty(Empl.retire) || string.IsNullOrEmpty(Empl.spouse) || 
   string.IsNullOrEmpty(Empl.children) || string.IsNullOrEmpty(Empl.bday) || 
   string.IsNullOrEmpty(Empl.hire)|| string.IsNullOrEmpty(Empl.death) || 
   string.IsNullOrEmpty(Empl.JobName) || string.IsNullOrEmpty(Empl.More) || 
   string.IsNullOrEmpty(Empl.AndMore))
{
    //Display message. Something like "Error: Name and Month is missing"
    return;
}

Any solution I've found so far to address this is time-consuming, and would require writing more code.

Is there any way to know which value is string.IsNullOrEmpty without having to change this IF statement too much? Worse-case, I can check every single statement separately, but I would prefer not doing this.

Thanks.

Upvotes: 0

Views: 1527

Answers (6)

Aven
Aven

Reputation: 501

I find this sort of an more elegant way to use ModelState.isValid.

Some reference: What is ModelState.IsValid valid for in ASP.NET MVC in NerdDinner?

For your model, you can add following annotation:

[Required(AllowEmptyStrings= false)]
public string Boo { get; set; }

When you do validation, try:

if (!ModelState.IsValid) 
{
  //Display message. Something like "Error: Name and Month is missing"
  return;
}

Upvotes: 3

Christopher von Blum
Christopher von Blum

Reputation: 90

If you use ASP.NET MVC maybe use DataAnnotations...

For the general c# context consider PostSharp aspect oriented library! Geat project!

Otherwise: Maybe a reflection solution using plain .NET ? (Created just for you! I think i keep for some own projects maybe)

Works with different types and you can control the targeted bindingflags.

Provides a common base class for your data transfer objects. (dto)

Reflection is performance optimized and working for generics as well!

public class Program
{
    public void Main()
    {
        Empl test = new Empl()
        {
            TestProp = "blub",
            TestInt = 1
        };

        if (test.ValidateProperties(Validations.CheckEmptyStringsAndZeroInts))
        {
            Console.WriteLine("validation passed");
        }
        else
        {
            Console.WriteLine("validation failed");
        }
    }
}
private static class Validations
{
    //put this in a static class with standard checks
    public static Func<object, bool> CheckEmptyStringsAndZeroInts = o =>
    {
        if (o is string && string.IsNullOrEmpty((string)o))
        {
                return false;
        }
        else if (o is int && ((int) o) == 0)
        {
            return false;
        }

        // ignore other property types
        return true;
    };
}
// Derive all your models like this. deriving from an Empl class is still valid and working!
//[IncludeBindingFlagsForPropertyReflctionAttribute(/*your custom binding flags*/)] //can also override the binding flags in derived classes!
public class Empl : DtoBase<Empl>
{
    public string TestProp { get; set; }

    public int TestInt { get; set; }

    // Your properties here
}

// Helps you to control the targeted properties. you can filter for public or protected members for example
public class IncludeBindingFlagsForPropertyReflctionAttribute : Attribute
{
    public BindingFlags BindingFlags { get; }
    public IncludeBindingFlagsForPropertyReflctionAttribute(BindingFlags propertySearchBindingFlags)
    {
        BindingFlags = propertySearchBindingFlags;
    }
}

//Looks much. But used once as base class can do those validations for you
[IncludeBindingFlagsForPropertyReflction(BindingFlags.Public | BindingFlags.Instance)]
public abstract class DtoBase<TDto> where TDto : DtoBase<TDto>
{
    private static Dictionary<Type, List<PropertyInfo>> DtoPropertyInfosStorage { get; }

    private List<PropertyInfo> DtoPropertyInfos => DtoPropertyInfosStorage[typeof (TDto)];

    static DtoBase()
    {
        DtoPropertyInfosStorage = new Dictionary<Type, List<PropertyInfo>>();

        Type tDto = typeof (TDto);

        var includeBindingFlagsForProperty = GetAttribute(tDto);

        BindingFlags defaultTargetFlags = BindingFlags.Instance | BindingFlags.Public;

        DtoPropertyInfosStorage.Add(typeof(TDto), new List<PropertyInfo>(typeof(TDto).GetProperties(includeBindingFlagsForProperty?.BindingFlags ?? defaultTargetFlags)));
    }

    private static IncludeBindingFlagsForPropertyReflctionAttribute GetAttribute(Type dtoType)
    {
        bool stopRecursion = !dtoType.IsSubclassOf(typeof(DtoBase<TDto>));

        var includeBindingFlagsForProperty = dtoType.GetCustomAttributes(typeof(IncludeBindingFlagsForPropertyReflctionAttribute)).FirstOrDefault();

        if (includeBindingFlagsForProperty == null && !stopRecursion)
        {
            return GetAttribute(dtoType.BaseType);
        }

        return null;
    }

    /// <summary>
    /// You can handle your validation type in you validation function yourself.
    /// </summary>
    public bool ValidateProperties(Func<object, bool> validationFunction)
    {
        foreach (KeyValuePair<Type, List<PropertyInfo>> dtoPropertyInfo in DtoPropertyInfosStorage)
        {
            foreach (PropertyInfo propertyInfo in DtoPropertyInfos)
            {
                if (!validationFunction(propertyInfo.))
                {
                    return false;
                }


            }
        }

        return true;
    }

    /// <summary>
    /// You can pass your targeted property type like string to TPropertyType
    /// <![CDATA[ Example:
    /// if(ValidateProperties<string>(validate => !string.IsNullOrEmpty(validate)))
    /// {
    ///     properties not empty?
    /// }
    /// ]]]]>
    /// </summary>
    public bool ValidateProperties<TPropertyType>(Func<TPropertyType, bool> validationFunction)
    {
        List<PropertyInfo> targetPropertyInfos =
            DtoPropertyInfos.Where(prop => prop.PropertyType == typeof (TPropertyType))
                .ToList();

        foreach (PropertyInfo dtoPropertyInfo in targetPropertyInfos)
        {
            if (validationFunction((TPropertyType) dtoPropertyInfo.GetValue(this)))
            {
                return false;
            }
        }

        return true;
    }
}

Upvotes: 0

luizluan
luizluan

Reputation: 21

using System.IO;
using System;
using System.Linq;


public class Program
{

    public class Dog
   {

    public static string Name {get;set;}
    public static string Race {get;set;}
   }

    public static bool validate(Dog dog)
    {
        bool val = true;
        var y  = dog.GetType()
                    .GetProperties()
                    .Select(p =>
                        {
                            object value =p.GetValue(dog,null);
                            if(string.IsNullOrEmpty(value.ToString())){ val=false; return false;}
                            else return true;

                        })
                    .ToArray();

         return val;
    }

    public static void Main()
    {
        Dog dog= new Dog();

        Dog.Name = "Peter";
        Dog.Race = "";

        if(validate(dog))
        {
             Console.WriteLine("Hello, World!");
        }


    }
}

Upvotes: 1

Xiaoy312
Xiaoy312

Reputation: 14477

You can use something like this :

public static class ValidationHelper
{
    public static IEnumerable<string> FindEmptyProperties<T>(T target, params Expression<Func<T, string>>[] propertySelectors)
    {
        foreach (var propertySelector in propertySelectors)
        {
            if (string.IsNullOrEmpty(propertySelector.Compile()(target)))
            {
                var memberExpr = propertySelector.Body as MemberExpression;
                yield return memberExpr.Member.Name;
            }
        }
    }
}

Usage :

var failed = ValidationHelper.FindEmptyProperties(Empl, x => x.Name, x => x.last, x => x.init, x => x.cat1).ToList();
if (failed.Any())
{
    throw new InvalidOperationException(
        string.Format("Error: {0} is missing", 
            string.Join(", ", failed)));
}

Upvotes: 0

Murray Foxcroft
Murray Foxcroft

Reputation: 13755

Yes, write your own string extension method that does the same check, but also takes in a List and add the field name to the list. Declare the list of strings before the if and you will have a list of offending fields where your comment is.

This can be improved upon with a bit of reflection to automatically get the name and maybe make a few optimizations but it is on the right track.

Keep in mind that the first condition that violates the if statement will cause it to fail, so you will get an incomplete list (of one item) unless your if is constructed differently.

 public static class StringExtensions
        {

            public static bool CheckIsNullOrEmptyAndListIt(this string field, string fieldName, List<string> naughties)
            {
                var result = String.IsNullOrEmpty(field);
                if (result == true)
                {
                    naughties.Add(fieldName);
                }

                return result;
            }         
        }
    }

Upvotes: 1

D Stanley
D Stanley

Reputation: 152566

No, there's no "magic" function that will tell you which of a series of expression in an OR statement are true. Also, since you're using the short-circuiting version, the statement will return true after the first true condition, so the remaining expressions are not even evaluated.

However, you could do something like this:

bool[] checks = {
   string.IsNullOrEmpty(Empl.Name) , string.IsNullOrEmpty(Empl.last) ,
   string.IsNullOrEmpty(Empl.init) , string.IsNullOrEmpty(Empl.cat1) ,
   string.IsNullOrEmpty(Empl.history) , string.IsNullOrEmpty(Empl.cat2) ,
   string.IsNullOrEmpty(Empl.year) , string.IsNullOrEmpty(Empl.month) , 
   string.IsNullOrEmpty(Empl.retire) , string.IsNullOrEmpty(Empl.spouse) , 
   string.IsNullOrEmpty(Empl.children) , string.IsNullOrEmpty(Empl.bday) , 
   string.IsNullOrEmpty(Empl.hire) , string.IsNullOrEmpty(Empl.death) , 
   string.IsNullOrEmpty(Empl.JobName) , string.IsNullOrEmpty(Empl.More) , 
   string.IsNullOrEmpty(Empl.AndMore)
};

if(checks.Any())
{
    //Display message. Something like "Error: Name and Month is missing"
    return;
}

now the checks variable holds the result of each expression.

Upvotes: 5

Related Questions