13

私は次のコードを持っています(フィールドへの変更を検出しようとしているため)

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

問題は、person.StateがNULLで、source.Stateが ""であるため、trueが返される場合があることです。

一方がnullで、もう一方が空の文字列である場合、それらを同等として扱い、データを更新しません。それを行う最もクリーンな方法は何ですか?これは一般的な問題のように見えるので、独自のComparerオブジェクトを作成する必要がありますか?

4

10 に答える 10

22

本当に必要な場合は、次のことを行うことができます。

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

ただし、ニーズによっては、person.Statenull値を返さないようにプロパティを変更することをお勧めします。

public class Person
{
    string _state = string.Empty;
    public string State
    {
        get { return _state; }
        set { _state = value ?? string.Empty; }
    }
}
于 2012-08-16T21:24:44.233 に答える
14

個人的には、アップストリームをサニタイズ/正規化しますが、ここで行う必要がある場合は、次のようにします。

// check different, treating null & "" as equivalent
if ((person.State ?? "") != (source.State ?? ""))
于 2012-08-16T21:23:59.963 に答える
12

他の答えは良いですが、読者にわかりやすくするために、それらを独自の方法に引き出します。

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

これは、これらの状態を複数の場所で比較する場合、または存在する場合は他の奇妙なケースを処理できるようにする場合に役立ちます。(例として、大文字と小文字を区別しないように変更する場合や、2つの状態がテキストで異なるが、一方が他方の省略形である場合、つまり「WI」を「ウィスコンシン」と等しくしたい場合があります。

于 2012-08-16T21:30:04.800 に答える
3

これを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);
于 2012-08-16T21:50:16.593 に答える
2

これは、拡張メソッドの完璧なソリューションのように聞こえます。

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

....または、拡張メソッドの本体を使用するだけです。これは、スタイルの問題としてはあまり見られないので、おそらく私が好むでしょう。

于 2012-08-17T00:54:08.077 に答える
2

Stringクラスには、文字列を受け取る関数「IsNullOrEmpty」があります。

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

ドキュメントから:

IsNullOrEmptyは、文字列がnullであるか、その値がEmptyであるかを同時にテストできる便利なメソッドです。これは、次のコードと同等です。

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

または、知っている、あるいは私は完全に比較を書き出すだろう:)

于 2012-08-17T03:40:28.007 に答える
1

これは一般的な問題のように見えるので、独自のComparerオブジェクトを作成する必要がありますか?

ここでの良い答えから、そうではないことは明らかですが、この種の比較を何度も行っている場合、または状態をキーとして使用したい場合は、次のようにします。

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);
  }
}
于 2012-08-16T21:46:55.773 に答える
1

与えられたすべての答えはトルコテストに失敗します。代わりにこれを試してください:

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);
}
于 2012-08-22T14:01:26.040 に答える
0

ええと、空とnullは同じものではないので、ここでは一般的な問題について言及していません。あなたの問題は、あなたのビジネスルールがその特定の評価が真実であると要求するドメインの問題です。次のようなメソッドはいつでも作成できます。

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

またはそのようなもの。そして、どこからでもそれを呼び出します。拡張メソッドにすることもできます。

于 2012-08-16T21:28:26.937 に答える
0

これはデコレータパターンの場合だと思います。あなたが望むことをするためにあなたはストック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
于 2012-08-16T23:53:47.883 に答える