views:

634

answers:

4

Is there a way to store a pointer to immutable types like strings in C#? How can execute: Instance1.SomeFunction(out MyString);

,and store a pointer to MyString inside of Instance1?

A: 

I have been fighting with pointers in C# for a while now, and was amazed by the lack of options. You encounter all kinds of obscure obstacles when dealing with pointers and pointer arguments in C#:

  • you cannot create native pointers to managed types, not even to strings
  • you cannot save immutable out/ref-arguments for later usage
  • you cannot have optional/nullable out/ref-arguments, even though "null" is the default state of string type
  • you cannot use passed out/ref-arguments inside lambda expressions

Pretty neat solution I found recently, and also the reason for this post is:

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

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

delegate void string_ptr(string a);
AareP
This should be an edit in the question.
configurator
And the delegate is not a pointer - it's a setter (you can't get the value with it).
configurator
Here's delegate with setter ability :) static void Main() { string s = "s"; test(a=>s=a??s); } static void test(string_ptr s) { string r1 = s(null); s("change string"); string r2 = s(null); } delegate string string_ptr(string a);
AareP
* setter ability -> getter ability
AareP
@AareP: interesting workaround.
configurator
A: 

Use this class as a pointer (note: untested notepad code, might need some fixing):

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;
    }
}

For example,

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";
}

Should output

10    PRINT "Hello, world!"
20    GOTO 10
configurator
For me renaming all string and int variables to box<string> and box<int> sounds like a lot of work. May be I'm too lazy.. :)
AareP
Think about it like this Box<int> is C#'s syntax for int*. It's the only replacement you'll find to pointers, I believe.
configurator
+1  A: 

In regards to the answer by the asker, what's wrong with:

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;
    }

}
Dave
Here you cannot store pointer to "s" for later use, for example if you would want to change it later, outside of MakeNull execution. You could do it with normal managed types, because objects are passed by reference by default, but not with immutable string type.
AareP
@AareP: Yes We Can (keep references to all sorts of managed stuff, all over the pace if we want to). You are not making much sense, or at least not explaining your problem(s) very well.
Henk Holterman
What I mean is that the following will have no effect on "s":void main(){ string s = "original string"; test1(ref s); test2();} static string r;static void test1(ref string s){ r = s;}static void test2(){ r = "changed string";}
AareP
Henk Holterman
Continued: You seem to want r to be a pointer-to-ref or ref-to-ref. C# can't do that on strings, on purpose. You can always approsch it by other means.
Henk Holterman
A: 

Ok, I found another partial solution to my problem. You can use overloading, if you want some ref/out-arguments to have null values:

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);
}
AareP
Ok, there is small bug with this solution, that I couldn't yet remove. Apparently c# doesn't support "===" operator, so I can't distinguish normal strings from "null_string"...
AareP