Jaka jest różnica między ciągiem a ciągiem w języku C #?


6504

Przykład ( zwróć uwagę na przypadek ):

string s = "Hello world!";
String s = "Hello world!";

Jakie są zasady korzystania z każdego z nich? A jakie są różnice?


72
@ORMapper, ale faktem jest, że stringjest to leksykalna konstrukcja gramatyki C #, podczas gdy System.Stringjest tylko typem. Bez względu na jakąkolwiek wyraźną różnicę wymienioną w jakiejkolwiek specyfikacji, nadal istnieje ta domniemana różnica, którą można przyjąć z pewną dwuznacznością. Sam język musi obsługiwać stringw taki sposób, aby implementacja nie była (całkiem) tak zobowiązana do rozważenia dla konkretnej klasy w BCL.
Kirk Woll,

106
@KirkWoll: Zgodnie ze specyfikacją języka, sam język musi uważać stringsię za dokładnie taki sam jak typ BCL System.String, nic więcej. To wcale nie jest dwuznaczne. Oczywiście, możesz zaimplementować własny kompilator, używając gramatyki C #, i użyć wszystkich znalezionych tokenów do czegoś dowolnego, niezwiązanego z tym, co jest zdefiniowane w specyfikacji języka C #. Jednak wynikowy język byłby tylko podobny do C #, nie można go uznać za C #.
LUB Mapper

88
Możesz używać stringbez dyrektywy użycia dla Systemu. Nie możesz tego zrobić String.
Wilsu

14
Dla kogoś pochodzącego z Algolu i Fortranu ta dyskusja pokazuje, że coś jest nie tak string. Należy go skracać System.String, ale jako alias wydaje się całkiem podobny, ale nie dokładnie to samo. Po kilku latach C #, choć powiedziałbym, że jest bezpieczny po prostu użyć string, a string.Format()nie martwić System.String.
Roland

8
@Sangeeta Co mówisz? System.StringKlasa nadal istnieje, a stringsłowo kluczowe jest nadal aliasem dla niego. Tak jak System.Int32i int. Są dosłownie tym samym.
Craig,

Odpowiedzi:


6103

stringto alias w języku C # dla System.String.
Więc technicznie nie ma różnicy. To jak int vs. System.Int32 .

Jeśli chodzi o wytyczne, ogólnie zaleca się korzystanie z niego za stringkażdym razem, gdy odwołujesz się do obiektu.

na przykład

string place = "world";

Podobnie, myślę, że ogólnie zaleca się stosowanie, Stringjeśli chcesz odnieść się konkretnie do klasy.

na przykład

string greet = String.Format("Hello {0}!", place);

Jest to styl, który Microsoft używa w swoich przykładach .

Wygląda na to, że wskazówki w tym obszarze mogły ulec zmianie, ponieważ StyleCop wymusza teraz stosowanie aliasów specyficznych dla języka C #.


163
Jeśli zdecydujesz się użyć StyleCop i postępujesz zgodnie z tym, powiesz, aby użyć typów specyficznych dla języka. Więc dla C # będziesz miał ciąg (zamiast Ciąg), int (zamiast Int32), pływak (zamiast Pojedynczy) - stylecop.soyuz5.com/SA1121.html
Dominic Zukiewicz

144
Zawsze używam aliasów, ponieważ zakładałem, że któregoś dnia może się to przydać, ponieważ działają one jako abstrakcja, dlatego mogą mieć zmienione implementacje bez mojej wiedzy.
Rob

37
Visual Studio 2015 mówi, że String.Format należy zmienić na string.Format, więc myślę, że Microsoft idzie w tym kierunku. Zawsze używałem również String do metod statycznych.
Sami Kuhmonen,

32
Po ich przeczytaniu zauważyłem, że kilka komentarzy jest po prostu niepoprawnych. @ DRAirey1 Z czasem przekonasz się, że stary sposób jest nadal najlepszy, jeśli wątpisz, to odważę się napisać kod C # bez użycia programu Visual Studio. Jest to praktycznie niemożliwe i sytuacja, która pojawia się od czasu do czasu w pracach programistycznych. @Vlad Nie musisz niczego importować, aby użyć String. @Abhi Twój komentarz jest bezcelowy i równie prawdziwy dla string.Format(). @KlitosG Nie, to nie jest prawda. Wszystkie działają dokładnie tak samo.
krowe2

46
Czy możesz dodać uwagę, że tak naprawdę jest różnica? Na przykład: nameof(string)nie będzie kompilować, ale nameof(String)będzie.
Jeroen Vannevel

3439

Dla kompletności, oto zrzut mózgu powiązanych informacji ...

Jak zauważyli inni, stringjest to pseudonim System.String. Kompilują się do tego samego kodu, więc w czasie wykonywania nie ma żadnej różnicy. To tylko jeden z aliasów w C #. Pełna lista to:

object:  System.Object
string:  System.String
bool:    System.Boolean
byte:    System.Byte
sbyte:   System.SByte
short:   System.Int16
ushort:  System.UInt16
int:     System.Int32
uint:    System.UInt32
long:    System.Int64
ulong:   System.UInt64
float:   System.Single
double:  System.Double
decimal: System.Decimal
char:    System.Char

Oprócz stringi objectaliasy mają wszystkie typy wartości. decimaljest typem wartości, ale nie pierwotnym typem w CLR. Jedynym prymitywnym typem, który nie ma aliasu, jest System.IntPtr.

W specyfikacji aliasy typu wartości są znane jako „typy proste”. Literały mogą być użyte dla stałych wartości każdego prostego typu; żadne inne typy wartości nie mają dosłownych postaci. (Porównaj to z VB, który pozwala na DateTimeliterały i ma też alias.)

Jest jeszcze jedna okoliczność, w której ma używać aliasów: kiedy wyraźnie określający typ podstawowy enum jest. Na przykład:

public enum Foo : UInt32 {} // Invalid
public enum Bar : uint   {} // Valid

To tylko kwestia sposobu spec definiuje enum deklaracji - część po dwukropku musi być integralną typu produkcję, która jest jednym wyrazem sbyte, byte, short, ushort, int, uint, long, ulong, char... w przeciwieństwie do typu produkcji, jak używane na przykład w deklaracjach zmiennych. Nie wskazuje to na żadną inną różnicę.

Wreszcie, jeśli chodzi o użycie: osobiście używam aliasów wszędzie do implementacji, ale typ CLR dla dowolnych interfejsów API. Naprawdę nie ma to większego znaczenia, którego używasz pod względem implementacji - spójność w zespole jest miła, ale nikogo to nie obchodzi. Z drugiej strony naprawdę ważne jest, aby odwoływać się do typu w interfejsie API, robiąc to w sposób neutralny językowo. Wywołana metoda ReadInt32jest jednoznaczna, podczas gdy nazwana metoda ReadIntwymaga interpretacji. Dzwoniący może na przykład używać języka, który definiuje intalias Int16. Projektanci .NET Framework podążały tego wzoru, dobre przykłady bycia w BitConverter, BinaryReaderi Convertklas.


82
Interesująca jest sytuacja dziedziczenia z wyliczeniem. Czy możesz wskazać w dokumentacji, dlaczego alias musi być używany do wyliczeń? Czy to znany błąd?
JaredPar

149
Znajduje się w sekcji 14.1 specyfikacji (nie mogę tutaj łatwo cytować, ponieważ jest za długi). Nie wyraźnie powiedzieć, że musisz użyć aliasu, ale aliasy są rodzajem traktowane jako własnych typów. To wszystko jest trochę dziwne.
Jon Skeet,

32
@PiPeep to, co jest bardziej zdumiewające niż duża liczba głosów pozytywnych, to oszałamiająca niska liczba głosów negatywnych (weź pod uwagę, że 5 pierwszych postów ma w sumie ponad 2000 głosów pozytywnych, a jednak tylko 1 głosowanie wśród nich wszystkich). Zwłaszcza jeśli weźmiesz pod uwagę fakt, że w każdej społeczności zawsze są „hejterzy”, naprawdę uważam to za po prostu niesamowite.
corsiKa

40
Jedną interesującą różnicą między stringi Stringjest to, że string' is a keyword in c#, so you can not use it as a variable name.For Ex: ciąg znaków = "hi"; //compiler error, but String String = "hi"; `jest dopuszczalne, podobnie jak Stringidentyfikator, a nie słowo kluczowe.
Sanjeev Rai

33
@SanjeevRai: Tak. Możesz użyć @stringdo utworzenia identyfikatora, który kończy się tak, stringjakby. To rodzaj mechanizmu ucieczki.
Jon Skeet

715

Stringoznacza System.Stringi jest to .NET Framework. stringto alias w języku C # dla System.String. Oba są kompilowane System.Stringw języku IL (Intermediate Language), więc nie ma różnicy. Wybierz, co lubisz i używaj tego. Jeśli kodujesz w języku C #, wolałbym, stringponieważ jest to alias typu C # i dobrze znany przez programistów C #.

Mogę powiedzieć to samo o ( int, System.Int32) itp.


3
`Jeśli kodujesz w C #, wolałbym napis, ponieważ jest to alias typu C # i dobrze znany programistom w C # - kiedy osoba C # nie zna frameworku .NET. +1, ponieważ myślę, że ogólnie jest to najlepsza odpowiedź, ale punkt, o którym wspominam, wydaje się dziwny.
MyDaftQuestions

4
Osobiście wolę używać „Int32”, ponieważ od razu pokazuje zakres wartości. Wyobraź sobie, że zaktualizowali typ „int” w późniejszych systemach o wyższych bitach. „int” in c jest najwyraźniej postrzegane jako „typ liczby całkowitej, z którym procesor docelowy najbardziej efektywnie pracuje” , i zdefiniowany jako „co najmniej 16 bitowy”. Wolę przewidywalną spójność tam, dziękuję bardzo.
Nyerguds

2
@MyDaftQuestions Zgadzam się. Jeśli cokolwiek miałoby sens konsekwentne używanie typów .net, ponieważ są one ignorantami językowymi, a typ jest oczywisty, niezależny od jakiegokolwiek języka (czy znam wszystkie osobliwości F # lub VB?).
Peter - Przywróć Monikę

5
@Nyerguds Istnieją dwa powody, aby po prostu się o to nie martwić. Jednym z nich jest to, że intjest zdefiniowany w specyfikacji języka C # jako 32-bitowa liczba całkowita bez względu na sprzęt. C #, pomimo wspólnego dziedzictwa w mgiełce czasu, tak naprawdę nie jest C. Zmiana intna 64-bitową liczbę całkowitą byłaby przełomową zmianą w specyfikacji i języku. Wymagałoby to również przedefiniowania long, ponieważ longobecnie jest to 64-bitowa liczba całkowita. Drugi powód, dla którego nie należy się martwić, jest nieistotny, ponieważ typy nigdy się nie zmienią, ale .NET jest wystarczająco abstrakcyjny, że w 99% przypadków nie musisz o tym myśleć. ;-)
Craig

5
@Craig wbijam na części starych formatami gier, gdzie nie trzeba myśleć o tym cały czas, choć. A następnie przy użyciu Int16, Int32i Int64to dużo bardziej przejrzyste w kodzie niż przy użyciu raczej nondescriptive short, intilong
Nyerguds

504

Najlepsza odpowiedź, jaką kiedykolwiek słyszałem o używaniu podanych typów aliasów w C #, pochodzi od Jeffreya Richtera w jego książce CLR Via C # . Oto jego 3 powody:

  • Widziałem wielu deweloperów zdezorientowany, nie wiedząc, czy użyć ciąg lub ciąg w kodzie. Ponieważ w języku C # ciąg (słowo kluczowe) jest dokładnie odwzorowany na System.String (typ FCL), nie ma różnicy i można go użyć.
  • W języku C # długie mapy na System.Int64 , ale w innym języku programowania, długie mogą być mapowane na Int16 lub Int32 . W rzeczywistości C ++ / CLI faktycznie traktuje długo jak Int32 . Ktoś czytający kod źródłowy w jednym języku mógłby łatwo błędnie zinterpretować intencję kodu, gdyby był przyzwyczajony do programowania w innym języku programowania. W rzeczywistości większość języków nie traktuje długo jako słowa kluczowego i nie skompiluje kodu, który go używa.
  • FCL ma wiele metod, które mają nazwy typów jako część nazw metod. Na przykład typ BinaryReader oferuje metody takie jak ReadBoolean , ReadInt32 , ReadSingle itp., A typ System.Convert oferuje metody takie jak ToBoolean , ToInt32 , ToSingle i tak dalej. Chociaż napisanie następującego kodu jest legalne, wiersz z float wydaje mi się bardzo nienaturalny i nie jest oczywiste, czy wiersz jest poprawny:
BinaryReader br = new BinaryReader(...);
float val  = br.ReadSingle(); // OK, but feels unnatural
Single val = br.ReadSingle(); // OK and feels good

Więc masz to. Myślę, że to są naprawdę dobre punkty. Nie używam jednak rad Jeffreya we własnym kodzie. Być może jestem zbyt utknięty w moim świecie C #, ale w końcu staram się, aby mój kod wyglądał jak kod frameworka.


24
Drugi punkt brzmi rzeczywiście jak z jakiegoś powodu nie do użytku string, intitp
MauganRa

15
@MauganRa I tak powinno być, autor książki wymienia te powody, dla których nie używa aliasów.
tomi.lee.jones

31
„Jeśli ktoś czyta kod źródłowy C #, powinien interpretować długo zgodnie ze specyfikacją języka, a nie inną specyfikacją języków”. To całkowicie mija się z celem. Nie chodzi o to, że ktoś zamierza błędnie interpretować kod, po prostu mózg może łatwo wyciągnąć błędne wnioski, gdy typ ma inne znaczenie niż to, co programista widzi na co dzień w innym kontekście. Wszyscy popełniamy błędy; użycie jawnie nazwanych typów zmniejsza prawdopodobieństwo tych błędów.
Darryl

10
+ Te powody podsumowują moje uczucia w tej sprawie. Kiedy po raz pierwszy zacząłem pisać w języku C # (pochodzącym z Java / C ++ / C), myślałem, że aliasy były brzydkie. Nadal tak się czuję, niestety większość świata nie zgadza się ze mną lub ich to nie obchodzi, dlatego używaj małych liter.
gusgorman

8
@ jinzai pytanie dotyczy C #, w którym longjest zdefiniowana jako 64-bitowa liczba całkowita ze znakiem, niezależnie od platformy lub kompilatora. Tak więc w niektórych przypadkach co najmniej, tak, to nie zależą od języka.
phoog

455

stringjest zastrzeżonym słowem, ale Stringjest tylko nazwą klasy. Oznacza to, że sam stringnie może być użyty jako nazwa zmiennej.

Jeśli z jakiegoś powodu chcesz zmiennej o nazwie string , zobaczysz tylko pierwszą z tych kompilacji:

StringBuilder String = new StringBuilder();  // compiles
StringBuilder string = new StringBuilder();  // doesn't compile 

Jeśli naprawdę potrzebujesz nazwy zmiennej o nazwie string , możesz użyć jej @jako prefiksu:

StringBuilder @string = new StringBuilder();

Kolejna krytyczna różnica: przepełnienie stosu wyróżnia je inaczej.


20
Pamiętaj, że dzwonienie do lokalnego @stringjest naprawdę bezcelowe, ponieważ nazwy mieszkańców są obecne tylko w PDB. Równie dobrze można to nazwać _stringczy coś takiego. Bardziej sensowne są rzeczy, które mają nazwy dostępne poprzez odbicie, w miejscu, gdzie @stringbyłoby imię członka "string".
Roman Starkov,

25
Należy również pamiętać o używaniu słowa zastrzeżonego, ponieważ nazwa zmiennej jest rażąco nieelegancka.
Elton

7
OP nie chce używać Ciągu lub Ciągu jako nazwy zmiennej. Poprosili o wyjaśnienie różnicy między tymi typami . Twoja odpowiedź służy jedynie do dodania więcej zamieszania IMO
Matt Wilko

1
@craig, jeśli piszesz oprogramowanie, aby nauczyć ludzi, jak wiązać węzły?
Simon_Weaver,

5
@Simon_Weaver węzły w ciągach? haha, miło. :-) Oczywiście możesz wybrać alternatywną nazwę, na przykład wątek. Zaczekaj chwilę ... D'oh!
Craig,

391

Jest jeszcze jedna różnica - nie można używać Stringbez using System;wcześniej.


14
domyślnie większość ludzi dodaje to w jakikolwiek sposób na górze pliku. VS robi to domyślnie w większości przypadków nie wszystkich!
IbrarMumtaz,

9
Domyślnie dodaję tylko usingwymagane przeze mnie instrukcje i jawnie usuwam wszystko, czego nie potrzebuję. Power Productivity Tools> „[x] Usuń i sformatuj zastosowania przy zapisywaniu”
JMD

2
@JMD Zmodyfikowałem plik szablonu .cs, więc nie ma w nim nawet żadnych instrukcji używania! Zmieniłem również szablon klasy na internal sealed.
ErikE

@JMD Nienawidzę tej funkcji. Czasami wprowadza zmiany w nietkniętych plikach, co utrudnia sprawdzenie, jakie rzeczywiste zmiany zawiera zestaw zmian. Oczywiście zazwyczaj usuwam „za pomocą spamu”, ale tylko aktywnie, nie automatycznie.
mg30rg

Może tak być w przypadku C #, ale nie wszystkich języków .NET. (Powershell domyślnie importuje przestrzeń nazw Systemu.)
FSCKur

311

Zostało to omówione powyżej; nie możesz jednak używać stringw refleksji; musisz użyć String.


6
Nie rozumiem, co oznacza ta odpowiedź i dlaczego została wzięta pod uwagę. Możesz użyć typeof(string)w refleksji. Przykład pierwszy: if (someMethodInfo.ReturnType == typeof(string)) { ... }Przykład drugi: var p = typeof(string).GetProperty("FirstChar", BindingFlags.NonPublic | BindingFlags.Instance);Gdzie musisz go użyć String, a nie string? Jeśli spróbujesz czegoś takiego jak Type.GetType("String")lub Type.GetType("string"), żadna nie znajdzie klasy, ponieważ brakuje przestrzeni nazw. Jeśli z jakiegoś głupiego powodu porównujesz .Nametyp z "string"rozróżnianiem wielkości liter, masz rację.
Jeppe Stig Nielsen

256

System.Stringjest klasą ciągów .NET - w C # stringjest aliasem System.String- więc w użyciu są takie same.

Jeśli chodzi o wytyczne, nie ugrzęznę zbytnio i po prostu używam tego, na co masz ochotę - w życiu są ważniejsze rzeczy, a kod i tak będzie taki sam.

Jeśli znajdziecie się systemy, w których konieczne jest budynek określić wielkość liczb całkowitych, którego używasz, a więc mają tendencję do używania Int16, Int32, UInt16, UInt32itd. To może wyglądać bardziej naturalnie używać String- i podczas poruszania się między różnymi językami .net to może uczynić rzeczy bardziej zrozumiałymi - w przeciwnym razie użyłbym łańcucha i int.


2
Wybierz jeden i bądź konsekwentny. Jeśli pracujesz gdzieś w stylu domu, użyj tego.
Alan B

3
niestety styl jest osobistą preferencją i może być zbyt drogi, aby egzekwować w dużej bazie kodu w kilku zespołach bez dedykowanego właściciela kodu. zawsze są ważniejsze kwestie do załatwienia niż łańcuch zamiast łańcucha. co sprowadza nas z powrotem do „ważniejszych rzeczy w życiu”
aiodintsov

Jest to zdecydowanie preferencja; na przykład: Wolę używać short, int, ushort, uintzamiast Int16, itd. Głównie dlatego, że jest to jak dowiedziałem. To prawda, że Int16łatwiej jest od razu zrozumieć dla osób z mniejszym doświadczeniem. +1 ode mnie!
Emma

210

Wolę .NETtypy pisane wielkimi literami (zamiast aliasów) ze względu na formatowanie. Te .NETtypy są barwione takie same jak innych typów obiektów (typy wartości są odpowiednie obiekty, mimo wszystko).

Słowa kluczowe warunkowe i kontrolne (jak if, switchi return) są pisane małymi literami i mają kolor ciemnoniebieski (domyślnie). I wolałbym nie mieć niezgodności w użyciu i formacie.

Rozważać:

String someString; 
string anotherString; 

11
Czy piszesz także kod w rodzaju: Int32 i = 1; Zamiast int i = 1; ? Wydaje się niespójne, aby nie używać aliasu ciągu, gdy jest on dostępny.
bytedev

29
@nashwan: właściwie tak, używam Int32 i=1;zamiast tego int i = 1; uważam, że ten pierwszy jest bardziej czytelny pod względem moich zamiarów: mianowicie, że chcę 32-bitową liczbę całkowitą ze znakiem.
NotMe

5
Cóż, myślę, że wszystko zależy od tego, czy programista myśli, że piszą kod C # (ciąg) czy kod .NET (ciąg). Osobiście przede wszystkim myślę, że piszę w C # (i to C # używa .NET).
bytedev

7
@Alex: miałem na myśli po prostu to, że wolę być bardzo specyficzny w kodowaniu, aby usunąć dwuznaczność.
NotMe

22
Na absolutnym drugim końcu spektrum prawie zawsze używamvar
tic

192

stringi Stringsą identyczne pod każdym względem (oprócz wielkich liter „S”). Tak czy inaczej, nie ma to wpływu na wydajność.

Małe litery stringsą preferowane w większości projektów ze względu na wyróżnianie składni


Jeffrey Richter zaleca stosowanie typu CLR we wszystkich przypadkach (CLR przez C #), aby uniknąć dokładnie tego rodzaju zamieszania, które ma tutaj miejsce.
Josh

Oczywiste jest, że niezależnie od tego, czy użyjesz S, czy s, spowoduje to powstanie tych pytań, więc zignoruj ​​Richtera. ;)
Brad Wilson

Richter oznaczał, że łańcuch nie powinien być opcją - Microsoft nie powinien mieć go w języku. Nie możesz głosować za Richerem - on jest legendą! :)
Joe Ratzer

1
Zgadzam się, że może być lepiej, aby nie mieć aliasy w ogóle. Ale biorąc pod uwagę, że je mamy, myślę, że można z nich korzystać (ale nie w nazwach metod itp.)
Jon Skeet,

10
„ciąg” nie jest tym samym, co „ciąg”. To znaczy „System.String”. Więc jeśli używasz „String”, musisz wpisać „using System”, aby dołączyć przestrzeń nazw
ThiagoAlves

185

C # to język używany razem z CLR.

string jest typem w C #.

System.String jest typem w CLR.

Gdy użyjesz C # wraz z CLR stringzostanie zamapowany na System.String.

Teoretycznie można zaimplementować kompilator C #, który wygenerował kod bajtowy Java. Rozsądnym Realizacja tego kompilatora najprawdopodobniej na mapie string, aby java.lang.Stringw celu współdziałania z biblioteki uruchomieniowym Java.


1
stringnie jest typem w C #; jest to słowo zastrzeżone, które odwzorowuje na typ w CLR.
CesarGon

@CesarGon: Zgodnie z ECMA-334, sekcja 8.2.1: „C # zapewnia zestaw predefiniowanych typów [...] Predefiniowanymi typami referencyjnymi są obiekt i ciąg znaków.”
Rasmus Faber

10
Zgodnie z ECMA-334, sekcja 9.4.3, „ciąg znaków” jest słowem kluczowym. :-) Zgadzam się z tobą, że „ciąg znaków” jest typem, jeśli skupiasz się na semantyce, ale powiedziałbym, że jest słowem kluczowym (tj. Słowem zastrzeżonym), jeśli skupiasz się na składni. Standard popiera oba punkty widzenia (być może zbyt dwuznacznie!). Dla mnie OP dotyczy składni, więc skupiam się na składni, kiedy patrzę na odpowiedzi, ale rozumiem również twój punkt widzenia. Co więcej, twoja odpowiedź w obecnej postaci może być interpretowana w ten sposób, że istnieją dwa różne typy: łańcuch i łańcuch, jeśli tak nie jest. Jedno jest odwzorowaniem na drugie.
CesarGon

Wyjaśnijmy to sobie. „ciąg” jest zastrzeżonym aliasem. To nie jest prawdziwy typ danych. Jest to coś, co wskazuje na coś innego. Możesz usunąć wszystkie te aliasy (lub po prostu nigdy ich nie używać) i mieć doskonale dobry język programowania.
Quarkly

168

Ten film na YouTube pokazuje praktycznie, jak się różnią.

Ale teraz długa odpowiedź tekstowa.

Kiedy mówimy o .NETistnieją dwie różne rzeczy jeden jest .NETramowy i drugi są języki ( C#, VB.NETetc), które wykorzystują te ramy.

wprowadź opis zdjęcia tutaj

System.String„ aka ”„ String ”(wielkie„ S ”) jest .NETramowym typem danych, a„ string ”to C#typ danych.

wprowadź opis zdjęcia tutaj

W skrócie „String” to alias (to samo, co nazywa się różnymi nazwami) „string”. Tak więc technicznie obie poniższe instrukcje kodu dają to samo wyjście.

String s = "I am String";

lub

string s = "I am String";

W ten sam sposób istnieją aliasy dla innych typów danych c #, jak pokazano poniżej: -

Obiekt System.Object, string: System.String, bool: System.Booleanbajt: System.Byte, sbyte: System.SBytekrótka: System.Int16i tak dalej

Teraz pytanie za milion dolarów z punktu widzenia programisty Więc kiedy używać „String” i „string”?

Pierwszą rzeczą, aby uniknąć zamieszania, używaj jednego z nich konsekwentnie. Ale z punktu widzenia najlepszych praktyk, kiedy robisz deklarację zmiennej, dobrze jest używać „łańcucha” (małych „s”), a gdy używasz go jako nazwy klasy, preferowany jest „Łańcuch” (wielkie „S”).

W poniższym kodzie lewa strona jest deklaracją zmiennej i zadeklarowana za pomocą „łańcucha”. Po prawej stronie wywołujemy metodę, aby „String” był bardziej sensowny.

string s = String.ToUpper() ;

25
„W skrócie” String ”to alias (to samo, co nazywa się różnymi nazwami)„ string ””. To nie jest poprawne: alias to „ciąg”.
Xavier Egea

3
kiedy deklarujesz zmienną, dobrze jest użyć „łańcucha” (małych „s”), a gdy używasz go jako nazwy klasy, wtedy preferowany jest „Ciąg” (duże „S”). Ta konwencja wydaje się już nieaktualna: jeśli korzystasz z programu Visual Studio 2015 i spróbujesz go napisać String, zasugeruj, aby „uprościć kod”, przenosząc go do string...
Massimiliano Kraus,

165

Małe litery stringto pseudonim System.String. Są takie same w C#.

Jest to debata nad tym, czy należy użyć typów systemów ( System.Int32, System.Stringetc.) rodzaje lub C# aliases( int, stringitp). Osobiście uważam, że powinieneś skorzystać C# aliases, ale to tylko moje osobiste preferencje.


4
Na tym polega problem, nie są to aliasy „C #”, tylko aliasy „C”. W języku C # nie ma natywnego „łańcucha” ani „int”, tylko cukier syntaktyczny.
Quarkly

16
nie jestem pewien, skąd pochodzi „C”, ponieważ specyfikacja języka C # 5 brzmi „Łańcuch słów kluczowych jest po prostu aliasem dla predefiniowanej klasy System.String”. na stronie 85, pkt 4.2.4. Wszystkie języki wysokiego poziomu są składniowe w porównaniu do zestawów instrukcji procesora i kodu bajtowego.
aiodintsov

156

stringjest tylko pseudonimem dla System.String. Kompilator potraktuje je identycznie.

Jedyną praktyczną różnicą jest podświetlanie składni, o czym wspominasz, i że musisz pisać, using Systemjeśli używasz String.


Nie trzeba poprzedzać Systemu, aby użyć String.
Joe Ratzer

18
using SystemPodczas używania musisz podać a String, w przeciwnym razie pojawi się następujący błąd:The type or namespace name 'String' could not be found (are you missing a using directive or an assembly reference?)
Ronald,

143

Oba są takie same. Ale z perspektywy wytycznych kodowania lepiej jest używać stringzamiast String. Tego właśnie używają programiści. np. zamiast używać Int32używamy intjako intalias doInt32

Do Twojej wiadomości „Ciąg słów kluczowych jest po prostu aliasem dla predefiniowanej klasy System.String”. - Specyfikacja języka C # 4.2.3 http://msdn2.microsoft.com/En-US/library/aa691153.aspx


120

Jak mówią inni, są tacy sami. Zasady StyleCop domyślnie wymusi na użycie stringjako kodu C # stylu najlepszych praktyk, z wyjątkiem gdy przedstawieniu System.Stringfunkcje statyczne, takie jak String.Format, String.Join, String.Concatitp ...


4
Nie wiedziałem, że StyleCop oznaczy użycie String - z wyjątkiem metod statycznych. Myślę, że jest to świetne, ponieważ zawsze tak go używam: ciąg znaków do deklaracji typu i ciąg znaków, gdy uzyskuję dostęp do elementów statycznych.
Goyuix,

101

Nowa odpowiedź po 6 latach i 5 miesiącach (zwlekanie).

Chociaż stringjest zarezerwowanym słowem kluczowym C #, które zawsze ma stałe znaczenie, Stringjest zwykłym identyfikatorem, który może odnosić się do czegokolwiek. W zależności od elementów bieżącego typu bieżąca przestrzeń nazw oraz zastosowane usingdyrektywy i ich umiejscowienie Stringmogą być wartością lub typem innym niż global::System.String.

Podam dwa przykłady, w których usingdyrektywy nie pomogą .


Po pierwsze, kiedy Stringjest wartością bieżącego typu (lub zmiennej lokalnej):

class MySequence<TElement>
{
  public IEnumerable<TElement> String { get; set; }

  void Example()
  {
    var test = String.Format("Hello {0}.", DateTime.Today.DayOfWeek);
  }
}

Powyższe nie zostanie skompilowane, ponieważ IEnumerable<>nie ma wywołanego elementu niestatycznego Formati nie stosuje się żadnych metod rozszerzenia. W powyższym przypadku nadal może być możliwe użycie Stringw innych kontekstach, w których typ jest jedyną możliwością składniową. Na przykład String local = "Hi mum!";może być OK (w zależności od przestrzeni nazw i usingdyrektyw).

Gorzej: powiedzenie String.Concat(someSequence)prawdopodobnie (w zależności od usings) przejdzie na metodę rozszerzenia Linq Enumerable.Concat. Nie przejdzie do metody statycznej string.Concat.


Po drugie, kiedy Stringjest inny typ , zagnieżdżony w bieżącym typie:

class MyPiano
{
  protected class String
  {
  }

  void Example()
  {
    var test1 = String.Format("Hello {0}.", DateTime.Today.DayOfWeek);
    String test2 = "Goodbye";
  }
}

Żadna instrukcja w Examplemetodzie się nie kompiluje. Tutaj Stringzawsze jest piano ciąg , MyPiano.String. Nie istnieje na nim żaden element członkowski ( staticani nie Formatjest on dziedziczony z jego klasy podstawowej). A wartości "Goodbye"nie można na nią przeliczyć.


4
Przypuszczam, że jestem diabelski, można: using String = System.Int32; using Int32 = System.String; a następnie policzyć błędy.
Steve

7
to jest poprawna odpowiedź. stringjest System.String. Stringmoże być cokolwiek.
Dave Cousineau,

Zgoda @DaveCousineau - o to chodzi w aliasie. Możesz utworzyć inny Stringtyp, który nie byłby ustawiony na obiekt System.String. Sprawdź: blog.paranoidcoding.com/2019/04/08/…
Kristopher

„Słowo kluczowe stringma konkretne znaczenie w języku C #. Jest to typ, System.Stringktóry istnieje w podstawowym zestawie wykonawczym. Środowisko wykonawcze w pełni rozumie ten typ i zapewnia możliwości, których twórcy oczekują stringsw .NET. Jego obecność jest tak ważna dla C #, że jeśli ten typ nie 't istnieje, kompilator zakończy działanie przed próbą nawet parsowania wiersza kodu. Stąd stringma precyzyjne, jednoznaczne znaczenie w kodzie C #. Identyfikator Stringnie ma jednak żadnego konkretnego znaczenia w C #. Jest to identyfikator, który przechodzi przez wszystkie reguły wyszukiwania nazw jako Widget, Studentitd ...”
Kristopher



87

W przeciwieństwie do tego, co wydaje się być powszechną praktyką wśród innych programistów, wolę bardziej Stringniż stringtylko po to, aby podkreślić fakt, że Stringjest to typ odniesienia, jak wspomniał Jon Skeet.



78

Chciałbym tylko dodać to do odpowiedzi lfousts z książki Ritchers:

Specyfikacja języka C # stanowi: „Ze względu na styl, użycie słowa kluczowego jest preferowane zamiast używania pełnej nazwy typu systemu”. Nie zgadzam się ze specyfikacją języka; Wolę używać nazw typów FCL i całkowicie unikać pierwotnych nazw typów. W rzeczywistości chciałbym, aby kompilatory nawet nie oferowały nazw typów pierwotnych i zmusiły programistów do używania zamiast nich nazw typów FCL. Oto moje powody:

  • Widziałem wielu deweloperów zdezorientowany, nie wiedząc, czy użyć ciąg lub ciąg w kodzie. Ponieważ w łańcuchu C # (słowo kluczowe) mapuje się dokładnie na System.String (typ FCL), nie ma żadnej różnicy i można go użyć. Podobnie słyszałem, jak niektórzy programiści mówili, że int reprezentuje 32-bitową liczbę całkowitą, gdy aplikacja działa w 32-bitowym systemie operacyjnym i że reprezentuje 64-bitową liczbę całkowitą, gdy aplikacja działa w 64-bitowym systemie operacyjnym. To stwierdzenie jest absolutnie fałszywe: w języku C # int zawsze mapuje na System.Int32 , a zatem reprezentuje 32-bitową liczbę całkowitą niezależnie od systemu operacyjnego, na którym działa kod. Jeśli programiści skorzystalibyInt32 w swoim kodzie, to potencjalne zamieszanie również zostaje wyeliminowane.

  • W języku C # długie mapy na System.Int64 , ale w innym języku programowania, długie mogą być mapowane na Int16 lub Int32 . W rzeczywistości C ++ / CLI długo traktuje jak Int32 . Ktoś czytający kod źródłowy w jednym języku mógłby łatwo błędnie zinterpretować intencję kodu, gdyby był przyzwyczajony do programowania w innym języku programowania. W rzeczywistości większość języków nie traktuje długo jako słowa kluczowego i nie skompiluje kodu, który go używa.

  • FCL ma wiele metod, które mają nazwy typów jako część nazw metod. Na przykład typ BinaryReader oferuje metody takie jak ReadBoolean , ReadInt32 , ReadSingle itp., A typ System.Convert oferuje metody takie jak ToBoolean , ToInt32 , ToSingle i tak dalej. Chociaż napisanie następującego kodu jest legalne, wiersz z float wydaje mi się bardzo nienaturalny i nie jest oczywiste, czy wiersz jest poprawny:

    BinaryReader br = new BinaryReader(...);
    float val = br.ReadSingle(); // OK, but feels unnatural
    Single val = br.ReadSingle(); // OK and feels good
  • Wielu programistów używających wyłącznie języka C # ma tendencję do zapominania, że ​​inne języki programowania mogą być używane przeciwko CLR, i dlatego z tego powodu do kodu biblioteki klas wkradają się organizmy C #. Na przykład Microsoft FCL jest prawie wyłącznie napisany w języku C # i deweloperów w zespole FCL teraz wprowadzono metody do biblioteki takiego jak Array „s GetLongLength , która zwraca Int64 wartość, która jest długo w C #, ale nie w innych językach (takich jak C ++ / CLI). Innym przykładem jest System.Linq.Enumerable jest LongCount metodą.

Nie otrzymałem jego opinii, zanim przeczytałem cały akapit.


72

String ( System.String) to klasa w bibliotece klas podstawowych. string (małe litery) to zarezerwowana praca w C #, która jest aliasem dla System.String. Int32 vs int jest podobną sytuacją Boolean vs. bool. Te słowa kluczowe specyficzne dla języka C # umożliwiają deklarowanie prymitywów w stylu podobnym do C.


67

Stringnie jest słowem kluczowym i może być używany jako identyfikator, natomiast stringjest słowem kluczowym i nie może być używany jako identyfikator. I z punktu widzenia funkcji oba są takie same.


67

To naprawdę kwestia konwencji. stringwygląda bardziej jak styl C / C ++. Ogólna konwencja polega na korzystaniu ze skrótów udostępnionych przez wybrany język (int / Int dla Int32). Dotyczy to również „obiektu” decimal.

Teoretycznie może to pomóc w przeniesieniu kodu do jakiegoś przyszłego standardu 64-bitowego, w którym może oznaczać „int” Int64, ale nie o to chodzi, i spodziewałbym się, że każdy kreator aktualizacji zmieni wszelkie intodniesienia do, Int32po prostu, aby był bezpieczny.


66

Spóźniam się na imprezę: używam typów CLR w 100% przypadków (cóż, z wyjątkiem sytuacji, gdy zmuszony jestem używać typu C #, ale nie pamiętam, kiedy to był ostatni raz).

Pierwotnie zacząłem robić to lata temu, zgodnie z książkami CLR autorstwa Ritchie. Miałem dla mnie sens, że wszystkie języki CLR ostatecznie muszą być w stanie obsługiwać zestaw typów CLR, więc użycie tych typów CLR zapewniło jaśniejszy i prawdopodobnie bardziej „wielokrotnego użytku” kod.

Teraz, gdy robię to od lat, jest to nawyk i podoba mi się ubarwienie, które VS pokazuje dla typów CLR.

Jedynym minusem jest to, że autouzupełnianie używa typu C #, więc kończę przepisywanie automatycznie generowanych typów w celu określenia typu CLR.

Również teraz, gdy widzę „int” lub „string”, wygląda mi to naprawdę źle, tak jak patrzę na kod C z 1970 roku.


49

Nie ma różnicy.

Słowo kluczowe C # stringodwzorowuje na typ .NET System.String- jest to alias, który utrzymuje konwencje nazewnictwa języka.

Podobnie intmapy do System.Int32.


W wersji 64-bitowej int odwzorowuje na System.Int64 (8 bajtów), w wersji 32-bitowej mapuje na System.Int32 (4 bajty)
Alex

1
IntPtr i UIntPtr to jedyne typy, które zmieniają rozmiar w zależności od platformy (pomijając rzeczywiste typy wskaźników, takie jak int*i typy złożone z [U] IntPtr lub rzeczywistych wskaźników).
P Daddy,

45

Cytat na ten temat z książki Daniela Solisa .

Wszystkie predefiniowane typy są mapowane bezpośrednio na podstawowe typy .NET. Nazwy typu C # (ciąg znaków) są po prostu aliasami dla typów .NET (String lub System.String), więc używanie nazw .NET działa poprawnie składniowo, chociaż jest to odradzane. W programie C # powinieneś używać nazw C # zamiast nazw .NET.


41

ciąg jest słowem kluczowym i nie można użyć łańcucha jako identyfikatora.

Łańcuch nie jest słowem kluczowym i można go użyć jako identyfikatora:

Przykład

string String = "I am a string";

Słowo kluczowe string jest pseudonimem System.Stringoprócz problemu ze słowem kluczowym, oba są dokładnie równoważne.

 typeof(string) == typeof(String) == typeof(System.String)

2
Jedyną niewielką różnicą jest to, że jeśli używasz klasy String, musisz zaimportować przestrzeń nazw System na wierzchu pliku, podczas gdy nie musisz tego robić, używając słowa kluczowego string.
Uttam

Istnieją proste przypadki użycia, w których instrukcja równości zawiodłaby ... Na przykład zdefiniowanie typu wywołania typu String w przestrzeni nazw bla i zaimportowanie tej przestrzeni nazw do pliku, w którym działa instrukcja równości.
Ricka

40

Tak, to nie jest różnica między nimi, podobnie jak booli Boolean.


40

@JaredPar (twórca kompilatora C # i płodny użytkownik SO!) Napisał świetny post na blogu na ten temat. Myślę, że warto się tutaj podzielić. To miłe spojrzenie na nasz temat.

stringvs. Stringnie jest debatą stylową

[...]

Słowo kluczowe stringma konkretne znaczenie w języku C #. Jest to typ, System.Stringktóry istnieje w podstawowym zestawie wykonawczym. Środowisko wykonawcze w pełni rozumie ten typ i zapewnia możliwości, których twórcy oczekują od ciągów w .NET. Jego obecność jest tak ważna dla C #, że jeśli ten typ nie istnieje, kompilator zakończy działanie przed próbą nawet parsowania linii kodu. Stąd stringma precyzyjne, jednoznaczne znaczenie w kodzie C #.

Identyfikator Stringnie ma jednak konkretnego znaczenia w języku C #. Jest to identyfikator, który przechodzi przez wszystkie reguły wyszukiwania nazw jako Widget, Studentitp. Może wiązać się z łańcuchem lub z innym typem zestawu, którego cele mogą być zupełnie inne niż string. Co gorsza, można go zdefiniować w taki sposób, jak kod String s = "hello"; kontynuował kompilację.

class TricksterString { 
  void Example() {
    String s = "Hello World"; // Okay but probably not what you expect.
  }
}

class String {
  public static implicit operator String(string s) => null;
}

Rzeczywiste znaczenie Stringzawsze będzie zależeć od rozpoznawania nazw. Oznacza to, że zależy to od wszystkich plików źródłowych w projekcie i wszystkich typów zdefiniowanych we wszystkich zestawach, do których istnieją odniesienia. Krótko mówiąc, potrzeba sporo kontekstu, aby wiedzieć, co to znaczy.

To prawda, że w zdecydowanej większości przypadków Stringi stringzwiąże się z tego samego typu. Ale używanie Stringnadal oznacza, że ​​programiści pozostawiają swój program do interpretacji w miejscach, gdzie jest tylko jedna poprawna odpowiedź. Kiedy Stringwiąże się z niewłaściwym typem, może programistom debugować godzinami, zgłaszać błędy w zespole kompilatora i generalnie marnować czas, który można by zaoszczędzić, używając string.

Innym sposobem na zwizualizowanie różnicy jest użycie tej próbki:

string s1 = 42; // Errors 100% of the time  
String s2 = 42; // Might error, might not, depends on the code

Wielu będzie argumentować, że chociaż informacje te są technicznie dokładne, używanie Stringjest w porządku, ponieważ niezwykle rzadko podstawa kodu definiuje typ tej nazwy. Lub, gdy Stringjest zdefiniowany, jest to znak złej bazy kodu.

[...]

Zobaczysz, że Stringjest zdefiniowany dla szeregu całkowicie ważnych celów: pomocników refleksji, bibliotek serializacji, leksykonów, protokołów itp. Dla każdej z tych bibliotek Stringvs. stringma realne konsekwencje w zależności od tego, gdzie jest używany kod.

Więc pamiętaj, kiedy widzisz debatę Stringkontra vs. stringdotyczy semantyki, a nie stylu. Wybór ciągu nadaje wyraźne znaczenie twojej bazie kodu. Wybór Stringnie jest zły, ale pozostawia otwarte drzwi dla niespodzianek w przyszłości.

Uwaga: skopiowałem / wkleiłem większość postów na blogu z przyczyn archiwalnych. Ignoruję niektóre części, więc jeśli to możliwe , polecam pominąć i przeczytać post na blogu .

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.