2014-05-20 14 views
11

Vengo da uno sfondo C++. Questa domanda è stata posta prima, ma prova come potrei non riuscire a trovare la risposta. Diciamo che ho:Ottieni una stringa per fare riferimento a un'altra in C#

string[] ArrayOfReallyVeryLongStringNames = new string[500]; 
ArrayOfReallyVeryLongStringNames[439] = "Hello world!"; 

Posso creare una stringa che fa riferimento al di sopra (nessuno di questi sarà la compilazione):

string a = ref ArrayOfReallyVeryLongStringNames[439]; // no compile 
string a = &ArrayOfReallyVeryLongStringNames[439];  // no compile 

Capisco che le stringhe sono immutabili in C#. Capisco anche che non è possibile ottenere l'indirizzo di un oggetto gestito.

mi piacerebbe fare questo:

a = "Donkey Kong"; // Now ArrayOfReallyVeryLongStringNames[439] = "Donkey Kong"; 

Ho letto la domanda Stack Overflow Make a reference to another string in C# che ha una risposta eccellente, ma ad una domanda leggermente diversa. NON voglio passare questo parametro a una funzione per riferimento. So come usare la parola chiave "ref" per passare un parametro per riferimento.

Se la risposta è "Non è possibile farlo in C#", c'è una soluzione comoda?

MODIFICA: Alcune risposte indicano che la domanda non era chiara. Lo chiedo in un modo diverso. Diciamo che dovevo manipolare tutti gli elementi dell'array con nome lungo originale che hanno indici primi. Mi piacerebbe aggiungere alias alias ... [2], Array ... [3], Array ... [5], ecc. A un elenco. Quindi, modifica gli elementi nell'elenco usando un ciclo "for" (magari passando l'elenco appena creato a una funzione).

In C# la parola chiave "using" crea un alias in una classe o uno spazio dei nomi. Dalle risposte, sembra che non sia possibile creare un alias in una variabile.

+1

La risposta, purtroppo, * è * "non puoi farlo", ma potresti andare "non sicuro" e accedere ai puntatori. – Jon

+0

È possibile creare un oggetto wrapper contenente una stringa da manipolare. – juharr

+8

Qual è il contesto qui? Perché non vuoi usare ArrayOfReallyVeryLongStringNames [439] direttamente? – qxg

risposta

5

Il più vicino si può ottenere è questo:

unsafe 
{ 
    string* a = &ArrayOfReallyVeryLongStringNames[439];  // no compile 
} 

che dà un'eccezione:

non può prendere l'indirizzo, ottenere la dimensione di, o dichiarare un puntatore a un tipo gestito ('stringa')

Quindi no, non è possibile ...

anche ri annuncio questo MSDN article che spiega che tipi può essere utilizzato (tipi blittable).

2

Quando faccio qualcosa di simile in C#:

string a = "String 1"; 
string b = a; 
a = "String 2"; 

Console.WriteLine(a); // String 2 
Console.WriteLine(b); // String 1 

Il fatto è che, sia "String 1" e "String 2" letterali vengono creati all'inizio del programma, e le corde sono sempre i puntatori: inizialmente un riferimento "String 1" letterale e successivamente fa riferimento a "String 2". Se vuoi che faccia sempre riferimento alla stessa cosa, in C# usi solo la stessa variabile.

The string objects themselves are immutable in C#:

Perché una stringa "modifica" è in realtà una nuova creazione stringa, è necessario prestare attenzione quando si creano i riferimenti a stringhe. Se si crea un riferimento a una stringa e quindi si "modifica" la stringa originale, il riferimento continuerà a puntare all'oggetto originale anziché al nuovo oggetto creato quando la stringa è stata modificata.

Quando è necessaria la mutevolezza della stringa, per esempio, per concatenare un sacco di stringhe più veloci, altre classi vengono utilizzati, come StringBuilder.

Per riassumere, quello che stai cercando di fare è impossibile.

2

In C#, una stringa è un oggetto. Pertanto, String a = "Donkey Kong" indica che a ha ora un riferimento a questa stringa assegnata alla memoria.Poi tutto quello che dovete fare è:

ArrayOfReallyVeryLongStringNames[439] = a; 

E che copierà il refrence (che si dovrebbe pensare di in C# !!!) per la posizione nella stringa.

MA !! Quando esegui a="new string";, a otterrai un nuovo riferimento. Vedere l'esempio che ho creato: http://prntscr.com/3kw18v

È possibile farlo solo con la modalità non sicura.

1

Si può creare un involucro

public class StringWrapper 
{ 
    public string Value {get;set;} 
} 

StringWrapper[] arrayOfWrappers = new StringWrapper[500]; 
arrayOfWrappers[439] = new StringWrapper { Value = "Hello World" }; 
StringWrapper a = arrayOfWrappers[439]; 
a.Value = "New Value"; 
0
 [TestMethod] 
    public void TestMethod1() 
    { 
     string[] arrayOfString = new string[500]; 
     arrayOfString[499] = "Four Ninty Nine"; 
     Console.WriteLine("Before Modification : {0} " , arrayOfString[499]); 

     string a = arrayOfString[499]; 

     ModifyString(out arrayOfString[499]); 

     Console.WriteLine("after a : {0}", a); 
     Console.WriteLine("after arrayOfString [499]: {0}", arrayOfString[499]); 

    } 

    private void ModifyString(out string arrayItem) 
    { 
     arrayItem = "Five Hundred less one"; 
    } 
+2

L'OP ha detto esplicitamente che NON voleva passare il parametro a una funzione. – juharr

12

Si può creare un involucro che mantiene un riferimento alla matrice sottostante e l'indice della stringa:

public sealed class ArrayStringReference 
{ 
    private readonly string[] _array; 
    private readonly int  _index; 

    public ArrayStringReference(string[] array, int index) 
    { 
     _array = array; 
     _index = index; 
    } 

    public string Value 
    { 
     get 
     { 
      return _array[_index]; 
     } 

     set 
     { 
      _array[_index] = value; 
     } 
    } 

    public override string ToString() 
    { 
     return Value; 
    } 
} 

allora questo lavoro :

string[] ArrayOfReallyVeryLongStringNames = new string[500]; 
    ArrayOfReallyVeryLongStringNames[439] = "Hello world!"; 

    var strRef = new ArrayStringReference(ArrayOfReallyVeryLongStringNames, 439); 
    Console.WriteLine(ArrayOfReallyVeryLongStringNames[439]); // Outputs "Hello world!" 
    strRef.Value = "Donkey Kong"; 
    Console.WriteLine(ArrayOfReallyVeryLongStringNames[439]); // Outputs "Donkey Kong" 

Si potrebbe fare questo più comodo da usare, fornendo un operatore stringa implicita in modo da non dover usare .Value per accedere alla stringa sottostante:

// Add this to class ArrayStringReference implementation 

public static implicit operator string(ArrayStringReference strRef) 
{ 
    return strRef.Value; 
} 

Poi, invece di dover accedere alla stringa di fondo in questo modo:

strRef.Value = "Donkey Kong"; 
... 
string someString = strRef.Value; 

è possibile farlo:

strRef.Value = "Donkey Kong"; 
... 
string someString = strRef; // Don't need .Value 

questo è lo zucchero sintattico, ma potrebbe rendere più facile per iniziare a utilizzare un ArrayStringReference nel codice esistente. (Si noti che è comunque necessario utilizzare .Value-impostare la stringa sottostante.)

1

cosa si sta cercando di fare è universalmente scoraggiati, e attivamente impedito, in C#, dove la logica dovrebbe essere indipendente dal modello di memoria , tuttavia, fare riferimento alla domanda SO relativa C# memory address and variable per alcune informazioni.

EDIT 1

Un approccio più canonica al vostro problema reale in C# sarebbe:

 // using System.Linq; 

     string[] raw = new string[] { "alpha", "beta", "gamma", "delta" }; 

     List<int> evenIndices = Enumerable.Range(0, raw.Length) 
      .Where(x => x % 2 == 0) 
      .ToList(); 

     foreach (int x in evenIndices) 
      raw[x] = raw[x] + " (even)"; 

     foreach (string x in raw) 
      Console.WriteLine(x); 

     /* 
     OUTPUT: 

     alpha (even) 
     beta 
     gamma (even) 
     delta 
     */ 

Se davvero si vuole modificare la struttura di memoria originale stesso, allora forse C++ è un linguaggio più appropriato scelta per la soluzione.

EDIT 2

Guardando in giro su SO, si consiglia di guardare a questa risposta Hidden Features of C#? ad una domanda non correlata.

+0

Non posso essere d'accordo sul fatto che questo è "scoraggiato universalmente" o che è "attivamente impedito". "using" e "ref" sono due parole chiave C# usate regolarmente. – AlainD

0

Certo che puoi, hehe:

var a = __makeref(array[666]); 
__refvalue(a, string) = "hello"; 

Ma si dovrebbe avere una buona ragione per farlo in questo modo.

Problemi correlati