[rozważania] Porównywanie stringów

0

W tym wątku poruszono kwestię porównania dwóch stringów i nie chcąc tam siać zamętu rozpocząłem nowy wątek.

Zazwyczaj pisałem

if (string1 == "abc") {}

ale widzę, że ta wersja jest niezalecana. To dość dziwne, że kompilator nie zamienia jej w takim razie na wersję "lepszą" - dlaczego?

Do wyboru mamy jeszcze:

if (string1.CompareTo("abc")) {}

oraz

if (string1.Equals("abc")) {}

do tego jeśli porównujemy string1 z łańcuchem pustym "" to można jeszcze użyć:

if (string1.Length == 0) { }

Której wersji używać najlepiej, dlaczego i dlaczego kompilator sam nie dobierze optymalnej, jeśli da się to prosto określić?

Jedyne, co kiedyś wyczytałem, to powinno się stosować Equals i dodać odpowiednie CultureInfo jeśli program jest wielojęzyczny i porównuje dane wprowadzane przez użytkownika [np. filtr czy wyszukiwanie].

0

Mam taki artykuł na temat porównywania stringów: http://www.codeproject.com/csharp/stringperf.asp?df=100&forumid=179078&exp=0&select=1675447&tid=1675447

Co do pytania dlaczego konstrukcja if (string1 == "abc") {}nie jest zamieniana na inną, lepszą to według mnie nie jest zamieniana ponieważ wszystkie te podane powyżej konstrukcje są poprawne i różnią się jedynie czasem wykonywania i ilością potrzebnej pamięci. Są jedynie zalecenia co do tego co lepiej i efektywniej wykorzystywać to jednak nie powód aby odbierać tę dowolność i narzucać programiście konkretny sposób porównywania.

0

Witam :)

Dawno nie pisalem tu ale cos i od siebie powiem:

Dla wgladu zamieszczam kody funkcji Equlas:


	public static bool Equals (string a, string b)
			
			{
				if (a == b)
				{
					return true;
				}
				else if (a == null)
				{
					return false;
				}
				else if (b != null)
				{
					return string.EqualsHelper (a, b);
				}
				else
				{
					return false;
				}
			}



private static unsafe bool EqualsHelper (string strA, string strB)
			
			{
				char* char_Ptr3;
				char* char_Ptr4;
				int i1 = strA.Length;
				if (i1 != strB.Length)
				{
					return false;
				}
				else
				{
					fixed (char* char_Ptr1 = (strA + RuntimeHelpers.OffsetToStringData))
					{
						fixed (char* char_Ptr2 = (strB + RuntimeHelpers.OffsetToStringData))
						{
							char_Ptr3 = char_Ptr1;
							char_Ptr4 = char_Ptr2;
							while (i1 >= 10)
							{
								if ((((((* char_Ptr3) != (* char_Ptr4)) || ((* (char_Ptr3 + 2)) != (* (char_Ptr4 + 2)))) || ((* (char_Ptr3 + 4)) != (* (char_Ptr4 + 4)))) || ((* (char_Ptr3 + 6)) != (* (char_Ptr4 + 6)))) || ((* (char_Ptr3 + 8)) != (* (char_Ptr4 + 8))))
								{
									break;
								}
								char_Ptr3 += 20;
								char_Ptr4 += 20;
								i1 -= 10;
							}
							while ((i1 > 0) && ((* char_Ptr3) == (* char_Ptr4)))
							{
								char_Ptr3 += 4;
								char_Ptr4 += 4;
								i1 -= 2;
							}
							return (i1 <= 0);
						}
					}
				}
			}

funkcji Compare:

public int CompareTo (string strB)
			
			{
				if (strB != null)
				{
					return CultureInfo.CurrentCulture.CompareInfo.Compare (this, strB, CompareOptions.None);
				}
				else
				{
					return 1;
				}
			}

public static int Compare (string strA, string strB)
			
			{
				return CultureInfo.CurrentCulture.CompareInfo.Compare (strA, strB, CompareOptions.None);
			}


//CompareInfo.Compare

public virtual int Compare (string string1, string string2)
			
			{
				return this.Compare (string1, string2, CompareOptions.None);
			}
			



//CompareInfo.Compare
		public unsafe virtual int Compare (string string1, string string2, CompareOptions options)
			
			{
				if (options == CompareOptions.OrdinalIgnoreCase)
				{
					return string.Compare (string1, string2, StringComparison.OrdinalIgnoreCase);
				}
				else if ((options & CompareOptions.Ordinal) != CompareOptions.None)
				{
					if (options == CompareOptions.Ordinal)
					{
						if (string1 == null)
						{
							if (string2 != null)
							{
								return -1;
							}
							else
							{
								return 0;
							}
						}
						if (string2 != null)
						{
							return string.nativeCompareOrdinal (string1, string2, false);
						}
						else
						{
							return 1;
						}
					}
					throw new ArgumentException (Environment.GetResourceString ("Argument_CompareOptionOrdinal"), "options");
				}
				else if ((options & (~ (CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreSymbols | CompareOptions.IgnoreKanaType | CompareOptions.IgnoreWidth | CompareOptions.StringSort))) != CompareOptions.None)
				{
					throw new ArgumentException (Environment.GetResourceString ("Argument_InvalidFlag"), "options");
				}
				else
				{
					if (string1 == null)
					{
						if (string2 != null)
						{
							return -1;
						}
						else
						{
							return 0;
						}
					}
					if (string2 == null)
					{
						return 1;
					}
					else if (! this.IsSynthetic)
					{
						return CompareInfo.Compare (this.m_pSortingTable, this.m_sortingLCID, string1, string2, options);
					}
					else if (options != CompareOptions.Ordinal)
					{
						return CompareInfo.nativeCompareString (this.m_sortingLCID, string1, 0, string1.Length, string2, 0, string2.Length, CompareInfo.GetNativeCompareFlags (options));
					}
					else
					{
						return CompareInfo.Compare (CultureInfo.InvariantCulture.CompareInfo.m_pSortingTable, this.m_sortingLCID, string1, string2, options);
					}
				}
			}






			

Sami wysnujcie wnioski ;)
niestety nie posiadam kodów funkcji operatorowej string.==

0

imho różnice mogą pojawić się przy logice - jeśli ustawienia regionalne i językowe będą specyficzne, mogą pojawić się błędy. Fajny przykład (Turkish-I Problem) podany jest na http://msdn2.microsoft.com/en-us/library/ms973919.aspx.

A jeśli chodzi o wybór metody - wydaje mi się, że dopóki w porównaniach nie używamy stringów mogących pochodzić spoza kodu aplikacji, można oprzeć się choćby na "==".

Jeśli chodzi o wydajność - we wspomnianym wątku cytowałem wspomniany tutaj artykuł z CodeProjecta (choć trochę wyrwałem cytat z kontekstu :)). Małe porównanie jest też tu: http://dotnetjunkies.com/WebLog/chris.taylor/archive/2004/05/18/13927.aspx

A tu parę off-topic'owych linków:

0

MrC - wiesz, wydaje mi sie ze wszyscy umieja uzywac Reflector'a, nie trzeba wiec smiecic bukwami kodu

1 użytkowników online, w tym zalogowanych: 0, gości: 1