2009-02-19 7 views
1

Есть ли способ сохранить указатель на неизменяемые типы, такие как строки в C#? Как выполнить: Instance1.SomeFunction (out MyString);Передача и сохранение указателей на неизменяемые типы и строки в C#

, а также сохранить указатель на MyString внутри экземпляра 1?

+0

Неясно, какую проблему вы пытаетесь решить здесь. Кому нужны указатели, когда строковые переменные уже являются ссылками? –

+0

C#, похоже, был * разработан *, чтобы скрыть указатели от программиста. Вообще говоря, манипуляция указателем излишне усложняет код C#, поскольку обычно существует гораздо более простой способ сделать то, что вы хотите. – Whatsit

+0

Если строковые переменные являются ссылками, почему следующее не будет влиять на «s»: void main() {string s = "original string"; test1 (ref s); test2(); } статическая строка r; static void test1 (строка ref s) {r = s; } static void test2() {r = "измененная строка"; } – AareP

ответ

0

Я уже некоторое время сражаюсь с указателями на C#, и был поражен отсутствием опций. Вы столкнетесь со всеми видами непонятных препятствий при работе с указателями и аргументы указателя в C#:

  • Вы не можете создавать собственные указатели на управляемые типы, даже в строки
  • вы не можете сохранить неизменные из/реф-аргументы для последующего использования использование
  • вы не можете иметь дополнительный/NULLABLE Out/реф-аргументов, даже если «нулевое» состояние по умолчанию типа строки
  • вы не можете использовать вырубились/реф-аргументов внутри лямбда-выражения

Довольно изящное решение я нашел в последнее время, а также причина этого поста:

void Test() 
{ 
    string ret = ""; 
    SomeFunction(a=>ret=a); 
} 

void SomeFunction(string_ptr str) 
{ 
    str("setting string value"); 
} 

delegate void string_ptr(string a); 
+0

Это должно быть редактирование в вопросе. – configurator

+0

И делегат не является указателем - это сеттер (вы не можете получить значение с ним). – configurator

+0

Вот делегат с способностью настройки: static void Main() { string s = "s"; тест (a => s = a ??с); } static void test (string_ptr s) { string r1 = s (null); s ("change string"); строка r2 = s (null); } делегат string string_ptr (строка a); – AareP

0

Используйте этот класс в качестве указателя (примечание: непроверенный код блокнота, может понадобиться некоторые крепления):

public class Box<T> { 
    public Box(T value) { this.Value = value; } 

    public T Value { get; set; } 

    public static implicit operator T(Box<T> box) { 
     return box.Value; 
    } 
} 

Например,

public void Test() { 
    Box<int> number = new Box<int>(10); 
    Box<string> text = new Box<string>("PRINT \"Hello, world!\""); 

    Console.Write(number); 
    Console.Write(" "); 
    Console.WriteLine(text); 

    F1(number, text); 

    Console.Write(number); 
    Console.Write(" "); 
    Console.WriteLine(text); 
    Console.ReadKey(); 
} 

void F1(Box<int> number, Box<string> text) { 
    number.Value = 10; 
    text.Value = "GOTO 10"; 
} 

выход должен

10 PRINT "Hello, world!" 
20 GOTO 10 
+0

Для меня переименование всех переменных строки и int в поле и в поле звучит как много работы. Может быть, я слишком ленив .. :) – AareP

+0

Подумайте об этом вот так. - синтаксис C# для int *. Я полагаю, это единственная замена, которую вы найдете указателям. – configurator

0

В отношении ответа со стороны спрашивающего, что случилось с:

class Program 
{ 
    static void Main() 
    { 
     string str = "asdf"; 
     MakeNull(ref str); 
     System.Diagnostics.Debug.Assert(str == null); 
    } 

    static void MakeNull(ref string s) 
    { 
     s = null; 
    } 

} 
+0

Здесь вы не можете сохранить указатель на «s» для последующего использования, например, если вы хотите изменить его позже, вне выполнения MakeNull. Вы можете сделать это с помощью обычных управляемых типов, потому что объекты передаются по ссылке по умолчанию, но не с неизменяемым типом строки. – AareP

+0

@AareP: Да, мы можем (держите ссылки на всевозможные управляемые вещи, все темпы, если мы хотим). Вы не имеете большого смысла или, по крайней мере, не очень хорошо объясняете свои проблемы. –

+0

Я имею в виду, что следующее действие не будет влиять на «s»: void main() { string s = "original string"; test1 (ref s); test2(); } статическая строка r; static void test1 (ref string s) { r = s; } static void test2() { r = "changed string"; } – AareP

0

Хорошо, я нашел еще один частичное решение моей проблемы. Вы можете использовать перегрузку, если вы хотите, чтобы некоторые ref/out-arguments имели нулевые значения:

void Test() 
{ 
    string ret1 = "", ret2 = ""; 
    SomeFunction(ref ret1, ref ret2); 
    SomeFunction(null, ref ret2); 
    SomeFunction(ref ret1, null); 
    SomeFunction(null,null); 
} 

string null_string = "null"; 

void SomeFunction(ref string ret1,ref string ret2) 
{ 
    if(ret1!=null_string) 
     ret1 = "ret 1"; 
    if(ret2!=null_string) 
     ret2 = "ret 2"; 
} 

// Additional overloads, to support null ref arguments 
void SomeFunction(string ret1,ref string ret2) 
{ 
    Debug.Assert(ret1==null); 
    SomeFunction(null_string,ret2); 
} 
void SomeFunction(ref string ret1,string ret2) 
{ 
    Debug.Assert(ret2==null); 
    SomeFunction(ret1,null_string); 
} 
void SomeFunction(string ret1,string ret2) 
{ 
    Debug.Assert(ret1==null&&ret2==null); 
    SomeFunction(null_string,null_string); 
} 
+0

Хорошо, есть небольшая ошибка с этим решением, которое я еще не смог удалить. По-видимому, C# не поддерживает оператор «===», поэтому я не могу отличить нормальные строки от «null_string» ... – AareP