if (person.State != source.State)
{
//update my data . .
}
问题在于,有些情况下 person.State 是 NULL,而 source.State 是 "",因此返回 true。
如果其中一个为 null,另一个为空字符串,则我希望将它们视为相等,并且不更新我的数据。最干净的方法是什么?我需要创建自己的 Comparer 对象吗?因为这似乎是一个通用问题。
if (person.State != source.State)
{
//update my data . .
}
问题在于,有些情况下 person.State 是 NULL,而 source.State 是 "",因此返回 true。
如果其中一个为 null,另一个为空字符串,则我希望将它们视为相等,并且不更新我的数据。最干净的方法是什么?我需要创建自己的 Comparer 对象吗?因为这似乎是一个通用问题。
如果你真的需要,你可以这样做:
if ((person.State ?? string.Empty) != (source.State ?? string.Empty))
{
// ...
}
然而,根据您的需求,更好的解决方案可能是修改您的person.State
属性,以便永远不返回null值。
public class Person
{
string _state = string.Empty;
public string State
{
get { return _state; }
set { _state = value ?? string.Empty; }
}
}
""
和 string.Empty
一样有效,更易于阅读,并且不容易被反射滥用... typeof(string).GetField("Empty").SetValue(null, " "); // evil
- Marc Gravellstring.Empty
更容易阅读。这一点有些因人而异。 - Jon Hanna个人而言,我会在上游进行过滤/归一化处理,但如果我必须在这里处理:
// check different, treating null & "" as equivalent
if ((person.State ?? "") != (source.State ?? ""))
虽然其他答案很好,但我会将它们单独放在一个方法中,以使读者更清楚明白:
public static bool StatesEqual(string first, string second)
{
return first ?? "" == second ?? "";
}
如果你需要在多个地方比较这些状态,或者需要处理其他特殊情况,这将非常有益。 (例如,将其更改为不区分大小写,或者如果两个状态在文本上不同但一个是另一个的缩写,即您希望"WI"等于"Wisconsin"。
你可能会认为,在String.Equals中应该有一个StringComparison枚举值来处理这个问题,或者在String.Compare中有一个CompareOptions枚举值来处理它,但实际上并没有。
无论如何,我认为最好的做法仍然是使用String.Equals。
string s1 = null;
string s2 = string.Empty;
bool areEqual = string.Equals(s1 ?? string.Empty, s2 ?? string.Empty);
// areEqual is now true.
就像这样,您可以轻松添加大小写或区分文化字符串比较选项...
bool areEqual = string.Equals(s1 ?? string.Empty, s2 ?? string.Empty, StringComparison.OrdinalIgnoreCase);
public static bool IsEqualNoNulls(this String str, string cmp) //bad name, but you get the point
{
return (str ?? "") == (cmp ?? "");
}
你可以选择使用扩展方法的参数或直接使用扩展方法体,我更倾向于后者,因为我认为这不是一个很大的风格问题。
String类有一个名为"IsNullOrEmpty"的函数,接受一个字符串作为参数。
http://msdn.microsoft.com/en-us/library/system.string.isnullorempty.aspx
根据文档:
IsNullOrEmpty是一种方便的方法,可同时测试一个字符串是否为null或其值是否为空。它等同于以下代码:
result = s == null || s == String.Empty;
例如:
if (!(string.IsNullOrEmpty(person.State) && string.IsNullOrEmpty(source.State)))
{
//update your data . .
}
或者您可以使用扩展方法,类似于@Earlz所概述的方法。
您可以在这里了解更多关于它们的信息http://msdn.microsoft.com/en-us/library/bb383977.aspx
因此,假设我有一个如下的扩展方法:
public static bool IsBlank(this string str)
{
return string.IsNullOrEmpty(str);
}
if(!(person.State.IsBlank() && source.State.IsBlank())
{
//do something
}
即使person.State或source.State为null,这个方法仍然有效,因为这个扩展方法看起来像是字符串类的方法,但实际上被转换为以字符串变量作为参数的静态方法(按照文档),所以即使该字符串变量没有设置为字符串的实例,它也可以愉快地工作。
请注意,如果您在阅读代码并尝试弄清楚当person.State或source.State设置为null时为什么会有效时,这种方法可能会在以后困扰您 :P
或者,你知道的,另一种方式就是将其完全写出来 :)
所有给出的答案都无法通过土耳其测试。请尝试使用这个:
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);
}
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();
}
}
或者基于另一个比较来进行,以防默认的==
比较不适用(实际上很少适用):
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);
}
}
空和null并不是同一回事,因此您并没有涉及到通用问题。您的问题属于领域问题,因为您的业务规则要求特定的评估结果为真。您可以编写一个类似以下代码的方法:
public static bool AreMyStringsCustomEqual(string s1, string s2) {
return (s1 == null || s1 == "" && s2 == null || s2 == "");
}
或者类似这样的东西。然后从任何地方调用它。你甚至可以将其作为扩展方法。
我认为这是使用装饰器模式的情况。您需要装饰一个股票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 ;
}
}
使用方法很简单:
StringComparer sc = new MySpecialStringDecorator( StringComparer.CurrentCultureIgnoreCase , Collapse.NullAndEmptyAndWhitespace ) ;
// go to town
StringComparer
,基于文化 - 当前、不变、序数或特定 - 大小写敏感性和等效规则,并为每个等效规则的装饰器创建一个单独的子类型。 :D - Nicholas Carey
Microsoft.VisualBasic
中是否有公共字符串比较例程来实现这个功能,因为这是 VB.NET 字符串的默认比较方式? - Mark Hurd