简体   繁体   English

在C#中,将字符串与null进行比较以及“”返回true的最佳方法是什么

[英]In C#, what is the best way to compare strings with null and “” return true

I have the following code (as i am trying to detect changes to a field) 我有以下代码(因为我试图检测字段的更改)

 if (person.State != source.State)
 {
      //update my data . .
  }

the issue is I am having cases where person.State is NULL and source.State is "" and thus returning true. 问题是我遇到的情况是person.State为NULL而source.State为“”,因此返回true。

If one is null and the other is an empty string, I want to treat them as equal and don't update my data. 如果一个为null而另一个是空字符串,我想将它们视为相等并且不更新我的数据。 What is the cleanest way of doing that? 这样做最干净的方法是什么? Do i need to create my own Comparer object as this seems like a generic problem 我是否需要创建自己的Comparer对象,因为这似乎是一个普遍的问题

You could, if you really need to, do: 如果你真的需要,你可以这样做:

if ((person.State ?? string.Empty) != (source.State ?? string.Empty))
{
    // ...
}

However, depending on your needs, a better solution might be to modify your person.State property to never return null values. 但是,根据您的需要,更好的解决方案可能是修改person.State属性永远不会返回空值。

public class Person
{
    string _state = string.Empty;
    public string State
    {
        get { return _state; }
        set { _state = value ?? string.Empty; }
    }
}

Personally, I'd sanitize/normalize upstream, but if I had to do it here: 就个人而言,我会对上游进行消毒/规范化,但如果我必须在这里进行:

// check different, treating null & "" as equivalent
if ((person.State ?? "") != (source.State ?? ""))

While the other answers are good, I would pull them out into their own method to make it clearer to the reader: 虽然其他答案都很好,但我会将它们引入自己的方法,以使读者更清楚:

public static bool StatesEqual(string first, string second)
{
  return first ?? "" == second ?? "";
}

This will be beneficial if you compare these states in multiple places, or allow you to handle other odd cases if there are any. 如果您在多个位置比较这些状态,或者允许您处理其他奇怪的情况,这将是有益的。 (Examples might be to change it to be case insensitive, or if two states are textually different but one is an abbreviation of another, ie you want "WI" to be equal to "Wisconsin". (示例可能是将其更改为不区分大小写,或者如果两个状态在文本上不同,但是一个是另一个的缩写,即您希望“WI”等于“Wisconsin”。

You'd think there would be a StringComparison enum value to handle this with String.Equals... or a CompareOptions enum value to handle it with String.Compare... but there is not. 你认为会有一个StringComparison枚举值来处理这个String.Equals ...或一个CompareOptions枚举值来处理它与String.Compare ...但没有。

In any case, I think you should still be using String.Equals as a best practice. 无论如何,我认为你仍然应该使用String.Equals作为最佳实践。

string s1 = null;
string s2 = string.Empty;

bool areEqual = string.Equals(s1 ?? string.Empty, s2 ?? string.Empty);

// areEqual is now true.

And like this you can add case or culture string compare options easily... 像这样你可以轻松添加案例或文化字符串比较选项...

bool areEqual = string.Equals(s1 ?? string.Empty, s2 ?? string.Empty, StringComparison.OrdinalIgnoreCase);

Do i need to create my own Comparer object as this seems like a generic problem 我是否需要创建自己的Comparer对象,因为这似乎是一个普遍的问题

It should be clear by now from the good answers here, that you don't, but if you are doing this sort of comparison over and over, or want to use the states as keys, then: 现在应该从这里的好答案中清楚地知道,你没有,但如果你反复进行这种比较,或者想要将状态用作键,那么:

public class NullEmptStringComparer : IComparer<string>
{
  public Equals(string x, string y)
  {
    return (x ?? string.Empty) == (y ?? string.Empty);
  }
  public int GetHashCode(string str)
  {
    return (str ?? string.Empty).GetHashCode();
  }
}

Or to base it on another comparison, in case the default == comparison isn't appropriate (which it rarely is, really): 或者基于另一个比较,如果默认==比较不合适(它很少,真的):

public class NullEmptCustStringComparer : IComparer<string>
{
  private readonly IComparer<string> _baseCmp;
  public NullEmptCustStringComparer(IComparer<string> baseCmp)
  {
    _baseCmp = baseCmp;
  }
  public Equals(string x, string y)
  {
    return _baseCmp.Equals(x ?? string.Empty, y ?? string.Empty);
  }
  public int GetHashCode(string str)
  {
    return _baseCmp.GetHashCode(str ?? string.Empty);
  }
}

This sounds like a perfect solution for a extension method. 这听起来像是扩展方法的完美解决方案。

    public static bool IsEqualNoNulls(this String str, string cmp) //bad name, but you get the point
    {
        return (str ?? "") == (cmp ?? "");
    }

.... or just using the body of the extension method, which I'd probably prefer, as I don't see this as too much of a style problem. ....或者只是使用我可能更喜欢的扩展方法的主体,因为我不认为这是一个太多的样式问题。

The String class has a function "IsNullOrEmpty" which takes in a string. String类有一个函数“IsNullOrEmpty”,它接受一个字符串。

http://msdn.microsoft.com/en-us/library/system.string.isnullorempty.aspx http://msdn.microsoft.com/en-us/library/system.string.isnullorempty.aspx

From the documentation: 从文档:

IsNullOrEmpty is a convenience method that enables you to simultaneously test whether a String is null or its value is Empty . IsNullOrEmpty是一种便捷方法,使您可以同时测试String是否为null或其值是否为 It is equivalent to the following code: 它等同于以下代码:

result = s == null || s == String.Empty;

For example: 例如:

if (!(string.IsNullOrEmpty(person.State) && string.IsNullOrEmpty(source.State)))
{
      //update your data . .
}

Alternatively you could use an extension method, similar to what is outlined by @Earlz 或者,您可以使用扩展方法,类似于@Earlz概述的方法

You can learn more about them here http://msdn.microsoft.com/en-us/library/bb383977.aspx 你可以在这里了解更多关于它们的信息http://msdn.microsoft.com/en-us/library/bb383977.aspx

Therefore, assuming I had an extension method like the following: 因此,假设我有一个如下所示的扩展方法:

public static bool IsBlank(this string str)
{
    return string.IsNullOrEmpty(str);
}

This will allow you to do something like 这将允许你做类似的事情

if(!(person.State.IsBlank() && source.State.IsBlank())
{
     //do something
}

The reason this works, even if person.State or source.State is null is because the extension method, while looking like a method of the string class, is actually converted to a static method with the string variable as it's argument (as per the documentation), so it'll happily work even if the string variable isn't set to an instance of string. 这个工作的原因,即使person.State或source.State为null ,因为扩展方法看起来像字符串类的方法,实际上转换为静态方法,字符串变量作为它的参数(根据文档),即使字符串变量未设置为字符串实例,它也会很愉快地工作。

Keep in mind, though, that doing it this way could trip you up at a later time if you're reading the code and trying to figure out why it works when person.State or source.State is set to null :P 但请记住,如果您正在阅读代码并尝试在person.State或source.State设置为null时尝试找出其工作原理,那么这样做可能会在以后绊倒您:P

Or, y'know, alternatively I'd just write out a comparison in full :) 或者,你知道,或者我只是写出一个完整的比较:)

All given answers will fail the Turkey Test . 所有给出的答案都将通过土耳其测试 Try this one instead: 试试这个:

public static bool StatesEqual(string first, string second)
{
    if (first == null || second == null)
        return false; // You can also use return first == second if you want to compare null values.

    return first.Equals(second, StringComparison.InvariantCulture);
}

Well, empty and null are not the same thing, so you're not referring to a generic problem here. 好吧,空和null不是一回事,所以你不是指这里的一般问题。 Yours is a domain problem where your business rules demand that particular evaluation as being true. 您的域名问题是您的业务规则要求特定评估为真。 You can always write a method that looks like this: 您总是可以编写一个如下所示的方法:

public static bool AreMyStringsCustomEqual(string s1, string s2) {
    return (s1 == null || s1 == "" && s2 == null || s2 == "");
}

Or something like that. 或类似的东西。 And then call it from everywhere. 然后从各处调用它。 You could even make it an extension method. 你甚至可以把它作为一种扩展方法。

I believe this is a case for the Decorator pattern. 我相信这是Decorator模式的一个案例。 You need to decorate a stock StringComparer to do what you want: 你需要装饰一个库存StringComparer来做你想要的:

public enum Collapse
{
  None                      = 0 ,
  EmptyAndWhitespace        = 1 ,
  NullAndWhitespace         = 2 ,
  NullAndEmpty              = 3 ,
  NullAndEmptyAndWhitespace = 4 ,
}

public class MySpecialStringComparerDecorator : StringComparer
{
  const   string         COLLAPSED_VALUE = "" ;
  private StringComparer instance ;
  private Collapse     rule     ;

  public StringComparer Decorate( StringComparer sc , Collapse equivalencyRule )
  {
    StringComparer instance = new MySpecialStringComparer( sc , equivalencyRule ) ;
    return instance ;
  }

  private MySpecialStringComparerDecorator( StringComparer comparer , Collapse equivalencyRule )
  {
    if ( comparer == null                                  ) throw new ArgumentNullException("comparer") ;
    if ( !Enum.IsDefined(typeof(Collapse),equivalencyRule) ) throw new ArgumentOutOfRangeException("equivalencyRule") ;

    this.instance = comparer ;
    this.rule     = equivalencyRule ;

    return ;
  }

  private string CollapseAccordingToRule( string s )
    {
        string collapsed = s ;
        if ( rule != Collapse.None )
        {
            if ( string.IsNullOrWhiteSpace(s) )
            {
                bool isNull  = ( s == null ? true : false ) ;
                bool isEmpty = ( s == ""   ? true : false ) ;
                bool isWS    = !isNull && !isEmpty ;

                switch ( rule )
                {
                    case Collapse.EmptyAndWhitespace        : if ( isNull||isWS          ) collapsed = COLLAPSED_VALUE ; break ;
                    case Collapse.NullAndEmpty              : if ( isNull||isEmpty       ) collapsed = COLLAPSED_VALUE ; break ;
                    case Collapse.NullAndEmptyAndWhitespace : if ( isNull||isEmpty||isWS ) collapsed = COLLAPSED_VALUE ; break ;
                    case Collapse.NullAndWhitespace         : if ( isNull||isWS          ) collapsed = COLLAPSED_VALUE ; break ;
                    default                                 : throw new InvalidOperationException() ;
                }
            }
        }
        return collapsed ;
    }

  public override int Compare( string x , string y )
  {
    string a     = CollapseAccordingToRule(x) ;
    string b     = CollapseAccordingToRule(y) ;
    int    value = instance.Compare(a,b);
    return value ;
  }

  public override bool Equals( string x , string y )
  {
    string a     = CollapseAccordingToRule(x) ;
    string b     = CollapseAccordingToRule(y) ;
    bool   value = instance.Equals(a,b) ;
    return value ;
  }

  public override int GetHashCode( string obj )
  {
    string s     = CollapseAccordingToRule(obj) ;
    int    value = instance.GetHashCode( s ) ;
    return value ;
  }

}

Usage is simple: 用法很简单:

StringComparer sc = new MySpecialStringDecorator( StringComparer.CurrentCultureIgnoreCase , Collapse.NullAndEmptyAndWhitespace ) ;

// go to town

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 C#比较4个字符串并忽略空字符串的最佳方法 - C# the best way to compare 4 strings and ignore the empty one C#比较双精度值和一系列值并返回两个文本值的最佳方法是什么 - C# What is the best way to compare a double value to a range of values and return two text values 比较c#字符串的最合适方法是什么 - What is the most appropriate way to compare c# strings 比较2个字符串是否为NULL或value的有效方法,如果在C#中不为NULL,则进行修整以进行比较 - Efficient way to Compare 2 strings for NULL or value and trim to compare if it's not NULL in C# 比较C#中忽略大小写的2个字符的最佳方法是什么? - What is the best way to compare 2 characters ignoring case in C#? 比较 c# 中两个对象的最佳方法是什么 - What is the best way to compare two objects in c# 在C#中比较复杂对象的两个列表的最佳方法是什么 - What is the best way to compare two list of complex object in c# 在C#中比较2个整数列表/数组的最佳方法是什么? - What is the best way to compare 2 integer lists / array in C# 比较 c# 中的枚举的最佳和高效方法是什么? - What is the best and performant way to compare enums in c#? 在字符串列表C#中搜索字符串的最佳方法是什么 - What is the best way to search for a string in a list of list of strings c#
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM