2009-11-25 3 views
32

Использование C# и .NET 3.5, что является лучшим способом справиться с этой ситуацией. У меня есть сотни полей для сравнения из разных источников (в основном строки). Иногда источник возвращает поле строки как null, а иногда и пустым. И, конечно, иногда в полях есть текст. Мое текущее сравнение strA! = StrB не разрезает его, потому что strA имеет значение null, а strB - «". Я знаю, что могу сделать string.IsNullOrEmpty, что приводит к двойному сравнению и некоторому уродству. Есть ли лучший способ справиться с этим? Я думал о методах расширения, но вы не можете расширять операторы.String Сравнить, где null и empty равны

Наверное, я ищу сексуальный способ сделать это.

+2

Вы можете не thave «источник» возвращает строку пустой, или это желательно иметь нулевую строку доступной? –

ответ

51

Поскольку у вас есть сотни сравнений сделать, это звучит как вы хотите, чтобы одна функция вызывала так, чтобы вы могли уменьшить беспорядок и повторение в вашем коде. Я не думаю, что есть встроенная функция, чтобы сделать нулевой/пустая строка/сравнение проверить все в одном, но вы можете просто сделать его самостоятельно:

static class Comparison 
{ 
    public static bool AreEqual(string a, string b) 
    { 
     if (string.IsNullOrEmpty(a)) 
     { 
      return string.IsNullOrEmpty(b); 
     } 
     else 
     { 
      return string.Equals(a, b); 
     } 
    } 
} 

Тогда вы могли бы просто использовать один вызов Ваша функция для каждого сравнения:

 if(Comparison.AreEqual(strA[0], strB[0])) { // ... } 
     if(Comparison.AreEqual(strA[1], strB[1])) { // ... } 
     if(Comparison.AreEqual(strA[2], strB[2])) { // ... } 
     if(Comparison.AreEqual(strA[3], strB[3])) { // ... } 

Этот подход также легче расширить, если позже вы обнаружите, что вам нужно беспокоиться о дополнительных ситуациях, например, игнорируя пробелы в начале или в конце строк; вы можете просто добавить больше логики к своей функции, чтобы сделать некоторую обрезку или что-то еще, и вам не придется вносить какие-либо изменения в сотни строк кода, вызывающих вашу функцию.

+0

String.Equals (a, b) также обрабатывает нулевое сравнение, поэтому может избавиться от string.IsNullOrEmpty() check https://msdn.microsoft.com/en-us/library/1hkt4325(v=vs .90) .aspx – abhaybhatia

+1

@abhaybhatia String.Equals (a, b) не считает null равным пустой строке, что и требовалось. Поэтому необходима проверка string.IsNullOrEmpty. –

54

не исключает дополнительное, лежащие в основе сравнения, но для фактора сексуальности, вы могли бы использовать что-то вроде этого:

(strA ?? "") == (strB ?? "") 

или чуть менее сексуален, но предпочтительный вид:

(strA ?? string.Empty) == (strB ?? string.Empty) 
+0

Ну, я пытался переделать сотни сравнений с методом расширения, но, полагаю, мне придется укусить пулю. Я могу закончить писать метод, который выполняет это за кулисами. Благодарю. – billb

+8

+1, но только часть с 'String.Empty' в ней! – user7116

+0

'string.Empty' не _quite_ как сексуальный (менее компактный), поэтому я включил оба, но да, использование' string.Empty' является предпочтительным. – iammichael

5

Что относительно

strA ?? "" == strB ?? "" 
2

Что случилось с string.IsNullOrEmpty()? Я уверен, что, поскольку он является частью платформы .NET, он оптимизирован и, вероятно, намного эффективнее, чем то, что вы или я могли бы написать. Это может быть не сексуально, но это работает. Напишите код, который легко читается, и пусть компилятор разбирает детали.

+0

Потому что есть две проверки, и теперь я должен заменить сотни сравнений со всем этим шумом. – billb

+0

Это может быть, но не удалось найти замену, чтобы помочь вам обновить код? – TLiebe

+0

Конечно, но разве вы не собираетесь заменять сотни сравнений? Как вы планируете эту замену '! =' Без ручного труда? –

9

Не так сексуально, как ??, но вы могли бы избежать двойного сравнения часть времени, если вы короткое замыкание:

string.IsNullOrEmpty(strA) ? string.IsNullOrEmpty(strB) : (strA == strB) 
0

Если у вас есть 2 набора полей в какой-то коллекции, вы можете использовать LINQ в своих интересах. Если они в каком-то коллекции, которая позволяет получить доступ к ним с помощью ключа и они оба имеют одинаковые ключи, вы можете использовать это (готовый для вставки в LINQPad):

Dictionary<string,string> fields1 = new Dictionary<string,string>(); 
Dictionary<string,string> fields2 = new Dictionary<string,string>(); 

fields1.Add("field1", "this"); 
fields2.Add("field1", "this"); 
fields1.Add("field2", "is"); 
fields2.Add("field2", ""); 
fields1.Add("field3", "a"); 
fields2.Add("field3", null); 
fields1.Add("field4", "test"); 
fields2.Add("field4", "test"); 

var test = 
from f1 in fields1 
    join f2 in fields2 
    on f1.Key equals f2.Key 
select (f1.Value ?? "") == (f2.Value ?? ""); 

test.Dump(); 

Если у вас есть наборы поля в 2-х индексированных коллекций в том же порядке, вы могли бы использовать что-то вроде этого:

string[] strings1 = { "this", "is", "a", "test" }; 
string[] strings2 = { "this", "", null, "test" }; 

var test = 
from s1 in strings1.Select((value,index) => new {value, index}) 
    join s2 in strings2.Select((value,index) => new {value, index}) 
    on s1.index equals s2.index 
select (s1.value ?? "") == (s2.value ?? ""); 

test.Dump(); 
0

растворы другие дали, в том числе один, который предлагает определить класс сравнения для строк, забыл написать новый GetHashCode для ваши строки.

Это означает, что ваша строка не может использоваться в классах, которые зависят от GetHashCode, например Dictionary<T> или HashSet<T>.

См Why is it important to override GetHashCode when Equals method is overridden?

Всякий раз, когда вы решили изменить концепцию равенства для любого класса, вы должны написать EqualityComparer для этого класса. Это гарантирует, что если в соответствии с вашим измененным определением равенства с объектами считаются равными, то их GetHashCode вернет равные значения.

public class NullStringComparer : EqualityComparer<string> 
{ 
    public override bool Equals(string x, string y) 
    { 
     // equal if string.Equals(x, y) 
     // or both StringIsNullOrEmpty 
     return String.Equals(x, y) 
      || (String.IsNullOrEmpty(x) && String.IsNullOrEmpty(y)); 
    } 

    public override int GetHashCode(string obj) 
    { 
     if (String.IsNullOrEmpty(obj)) 
      return 0; 
     else 
      return obj.GetHashCode(); 
    } 
} 

Использование:

public static void Main() 
{ 
    string x = null; 
    string y = String.Empty; 

    Console.WriteLine($"Standard string comparison: {StringComparer.Ordinal.Equals(x, y)}"); 

    IEqualityComparer<string> equalityComparer = new NullStringComparer(); 
    Console.WriteLine($"My string comparison {equalityComparer.Equals(x, y)}"); 

    int hashX = equalityComparer.GetHashCode(x); 
    int hashY = equalityComparer.GetHashCode(y); 
    Console.WriteLine($"hash X = {hashX}, hash Y = {hashY}"); 
}