开发者

c#: keep ref parameter from constructor in class

开发者 https://www.devze.com 2023-02-15 20:36 出处:网络
Basically i would like to be able to have a reference to a variable inside a instance of a class, but i\'d like the reference to become a class variable so I dont need to send it around inside of the

Basically i would like to be able to have a reference to a variable inside a instance of a class, but i'd like the reference to become a class variable so I dont need to send it around inside of the class as parameter

code:

int num = 0;
myClass(num);
print num; // output is 0 but i'd like it to be 10 :)
class myClass
{
    private int classNumber;
    myClass(ref int number)
    {
        print number; //output is 0

        // id like this to be a reference to the refenrence
        classNumber = number;

        DoSomething();
    }
    public void DoSomething()
    {
        ClassNumber = 10;
    }
}

why i'm asking this is because i'm working with winforms and having a main form sending an instanc开发者_运维百科e of a class to a new form that should edit the class and send it back.. right now i use Form.ShowDialog() to avoid the user to use the main form while editing in the new form and after that grabbing the data from the new forms

editForm edtfrm = new editForm(ref instanceOfClass);
edtfrm.showDialog();
//grab the instance back
instanceOfClass = edtfrm.editedClass;

How can i solve this? i don't like this solution


i would like to be able to have a reference to a variable inside a instance of a class, but i'd like the reference to become a class variable so I dont need to send it around inside of the class as parameter

You will have to live with disappointment then. The CLR type system explicitly forbids storage of references to variables as members of classes. The CLR permits references to variables to be

  • passed to methods as arguments corresponding to formal parameters or 'this'
  • stored as locals
  • returned as method return values

but does not permit storage in arrays, fields, and so on. Basically, anything that goes "on the heap" can't hold onto a ref.

C# exposes the first feature: refs to variables as method parameters. It does not expose the other two features (though I have written an experimental version of C# which does, and it works quite nicely.)

Note that C# does not allow you to use refs in contexts which would require heap storage of the ref -- like a ref parameter being a closed-over outer variable of a lambda, for example. There are a few rare cases in which the compiler does allow what looks like long-term storage of the ref, and uses copy-in-copy-out semantics to emulate the ref, but probably best to not even go there.

Why does the CLR have this restriction? The right way to think about it is that there are two kinds of storage: long term and short term, usually called "heap" and "stack". But the shape of the data structure is irrelevant; what is relevant is the length of the lifetime. A variable has a storage location; that's what a variable is. If you could keep a ref to a variable allocated from the short-term storage in a long-term storage then the long-term storage keeps a ref to something that is of shorter lifetime, and therefore might crash and die when it accesses the variable after its death.

Obviously there are many ways to solve this problem. For example, the CLR team could have chosen to make it illegal to take a ref to short-term storage, and allow storage of refs in long-term storage. But that then means that you can't take refs to local variables or parameters, which you would like to put in short-term storage because their lives are so short.

The way the CLR team actually chose was to disallow long-term storage of any ref. Like any design decision, it was the result of many tradeoffs against competing goals.


It's not really a good idea what you are trying to do, I would expose the modified object as a property of the class like below:

public class ClassContructorReference
{
    static void Main(string[] args)
    {
        object var = new object();
        MyClass myClass = new MyClass(var);
        StringBuilder mySb = myClass.Instance as StringBuilder;
        Console.WriteLine(mySb.ToString());
    }
}

public class MyClass
{
    public object Instance {get;set;}

    public MyClass(object var)
    {
        this.Instance = var;
        DoSomething();
    }

    private void DoSomething()
    {
        this.Instance = new StringBuilder("Hello");
    }
}


Ofcourse your test code will not work as it is a primitive type.but your 2nd code will work as it is a reference type.(even 'ref' is not needed)No need to assign the instance back.

public class Second
{
    public First f;

    public Second(First f)
    {
        this.f= f;
    }

    public void change()
    {
        this.f.Name = "PUli";
    }
}
public class First
{
    private string _name;

    public First()
    {
        Name = "SUli";
    }

    public string Name
    {
        get { return _name; }
        set { _name = value; }
    }
}
class Program
{
    static void Main(String[] args)
    {
        First f = new First();
        Second sec = new Second(f);
        Console.WriteLine(f.Name);
        sec.change();
        Console.WriteLine(f.Name);
    }
}

Output:-

SUli

PUli


Create a class containing your number as a property and pass it across your logic. That class will represent your "Model".


You can't save a ref parameter, a ref isn't a reference, it is just an alias. If you have:

public void Stuff (ref int i)
{
  i = 2;
}

and call it:

int s = 1;
Stuff(ref s);

The ref means "make i an alias for s and propagate the change to it". Once you leave the scope of the method, that alias is gone. Incidently, Eric Lippert started a series about that on his blog.

You should create a class and use that in your logic. The GUI shouldn't manipulate values, only the backend should.


Couple of things here. First, in your constructor you probably wanna do

DoSomething();     
number=classnumber;

instead of

classnumber=number;

Second, Try

myClass(ref num);

instead of

myClass(num);


This is a very old question but I think you can do what you want with a little trick which involves capturing.

For example:

int meh = 9;

MyClass myClass = new(() => meh, o => meh = o);

meh = 768;

Console.WriteLine(myClass.CapturedInt); // Displays 768

myClass.CapturedInt = 1024;

Console.WriteLine(meh); // Displays 1024

class MyClass
{
    private readonly Func<int> readMethod;
    private readonly Action<int> writeMethod;

    public int CapturedInt
    {
        get => readMethod();
        set => writeMethod(value);
    }

    public MyClass(Func<int> read, Action<int> write)
    {
        readMethod = read;
        writeMethod = write;
    }
}

And here it is closer to your example:

int num = 0;

MyClass myClass = new(() => num, o => num = o);

Console.WriteLine(num); // Displays 10

class MyClass
{
    private readonly Func<int> readMethod;
    private readonly Action<int> writeMethod;

    public MyClass(Func<int> read, Action<int> write)
    {
        readMethod = read;
        writeMethod = write;

        DoSomething();
    }

    public void DoSomething()
    {
        writeMethod(10);
    }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消