【问题标题】:Any easy way to see which IF condition is false?有什么简单的方法可以查看哪个 IF 条件为假?
【发布时间】:2016-10-09 05:22:08
【问题描述】:

我发布这个问题是为了找到一种更简单的方法来获得结果。

我们有一个大的IF 语句,用于检查NULLstring.empty。像这样的:

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;
}

到目前为止,我发现的任何解决方案都非常耗时,并且需要编写更多代码。

有没有什么方法可以知道哪个值是string.IsNullOrEmpty 而不必过多地更改这个 IF 语句?更糟糕的是,我可以单独检查每个语句,但我不想这样做。

谢谢。

【问题讨论】:

  • 我不会这样做。我会想办法将它们封装到 Employee 类中。通过契约、前提条件和合理的默认值来思考编程。

标签: c# asp.net .net-4.0


【解决方案1】:

我发现这种使用 ModelState.isValid 的方式更优雅。

部分参考:What is ModelState.IsValid valid for in ASP.NET MVC in NerdDinner?

对于您的模型,您可以添加以下注释:

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

当您进行验证时,请尝试:

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

【讨论】:

    【解决方案2】:

    如果你使用 ASP.NET MVC 可能会使用 DataAnnotations...

    对于一般 c# 上下文,请考虑 PostSharp 面向方面的库!好项目!

    否则:也许是使用普通 .NET 的反射解决方案? (专为您创建!我想我可能会保留一些自己的项目)

    适用于不同类型,您可以控制目标绑定标志。

    为您的数据传输对象提供一个通用基类。 (dto)

    反射经过性能优化,也适用于泛型!

    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;
        }
    }
    

    【讨论】:

      【解决方案3】:
      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!");
              }
      
      
          }
      }
      

      【讨论】:

      • 仅适用于字符串。如果您想与其他人一起检查,请添加更多 ifs。
      • 如果两个值都不为空或 null ,他会写 Hello World 。如果你想让它做其他事情,那就只有否认。如果(!验证(狗)){}
      【解决方案4】:

      你可以使用这样的东西:

      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;
                  }
              }
          }
      }
      

      用法:

      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)));
      }
      

      【讨论】:

        【解决方案5】:

        是的,编写您自己的字符串扩展方法来执行相同的检查,但也接受一个列表并将字段名称添加到列表中。在 if 之前声明字符串列表,您将获得您的评论所在的违规字段列表。

        这可以通过一些反思来改进,以自动获取名称并可能进行一些优化,但它在正确的轨道上。

        请记住,违反 if 语句的第一个条件将导致它失败,因此除非您的 if 构造不同,否则您将得到一个不完整的列表(一个项目)。

         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;
                    }         
                }
            }
        

        【讨论】:

          【解决方案6】:

          不,没有“魔术”函数可以告诉您 OR 语句中的一系列表达式中的哪一个是正确的。此外,由于您使用的是短路版本,因此该语句将在第一个 true 条件之后返回 true,因此剩余的表达式 甚至不会被评估

          但是,您可以执行以下操作:

          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;
          }
          

          现在checks 变量保存了每个表达式的结果。

          【讨论】:

          • 谢谢。我最终使用了这样的东西。有没有一种简单的方法来映射,例如,bool[1]Empl.last?这样我就知道失败了。
          猜你喜欢
          • 1970-01-01
          • 2015-10-01
          • 2015-03-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-08-18
          • 2011-11-03
          • 1970-01-01
          相关资源
          最近更新 更多