-1

I have a class called Category that takes a variadic constructor. The arguments are strings.

class Category
{
    string[] definedSets;  // Sets supplied to the constructor

    public Category(params string[] specifiedSets)
    {
        definedSets = specifiedSets;
    }

etc.

A call to the constructor might look like Category myCat = new Category(myString1, myString2);

The problem is that I would like definedSets to change if the content of myString1 or myString2 changes. I tried definedSets = ref specifiedSets;, but I get an error The left hand side of a ref assignment must be a ref variable and I don't know how to resolve that.

Am I on the right track here? What do I do?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Charles
  • 479
  • 1
  • 3
  • 13
  • 1
    To use a ref local assignment, the original variable needs to be a by-reference variable. There's not enough context in your question to know how to answer it properly. Most likely, what you want to do simply can't be done, because you're misusing the original parameter variables (note that in the example you posted, the parameters _don't even need to be variables_ ...any expression that returns a `string` value would be legal, so getting the "reference" of the parameter doesn't make sense). But to the extent that this might be possible at all, you need to clarify your post. – Peter Duniho Jun 19 '21 at 17:35
  • 1
    Note that in addition to my previous comment, the error you're getting is actually complaining about the `definedSets` variable, which _also_ needs to be `ref` for a `ref` assignment to be legal. But that's a moot point, unless you can contrive a way for the constructor parameters themselves to also be `ref` values. – Peter Duniho Jun 19 '21 at 17:37
  • 1
    I hear you. Should I post a new question? Or just comment here? Dropping back one level, the question becomes something like "how can a class constructor get references (in the natural language sense of reference, not in a C# specific sense) to external strings such that if the content of one of the strings changes, methods in the class will see the new value, not the value at constructor time? In C/C++ this would be fairly easy. I say that not to slam C#; it is just that I am much more familiar with C++ and am learning C#. – Charles Jun 19 '21 at 18:24
  • 1
    If you can simply edit this question to improve it, that's sufficient. Though, bear in mind that now that answers are posted, you should take care to only _improve_ the question and not actually _make it different_, otherwise the posted answers no longer make sense (well, IMHO they were posted prematurely and so may not make sense in any case...but _community guidelines_ argue against invaliding existing answers, even if I personally don't think it matters much in this case). – Peter Duniho Jun 19 '21 at 18:51

3 Answers3

1

strings are immutable, and you can not change their value. Whenever you assign a new value it allocates new memory. It is not possible to refer to the same memory location every time.

I would suggest to use the StringBuilder class and change type of definedSets to StringBuilder,

public class Category
{
    StringBuilder[] definedSets;  // Sets supplied to the constructor

    public Category(StringBuilder specifiedSets)
    {
        this.definedSets = specifiedSets;
    }
}

Proof of concept: .NET Fiddle

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Prasad Telkikar
  • 15,207
  • 5
  • 21
  • 44
1

For that to work, you would have to wrap the strings in a custom wrapper class:

public class StrWrapper
{
    public string Value {get; set;}
    public StrWrapper(string val) => Value = val;
}

You can pass the object reference around and change the string inside it at any time.

Also note that you cannot save a string ref: https://stackoverflow.com/a/2982037/1974021 So even if you could get the ctor to accept a (string ref)[] array, you could only use it then & there and not store it.

DasKrümelmonster
  • 5,816
  • 1
  • 24
  • 45
  • Your link is misleading. That question discusses the immutability of the `string` type, which is completely different from the reason you can't save a ref local in a class field. A better link would be this one: https://stackoverflow.com/questions/2980463/how-do-i-assign-by-reference-to-a-class-field-in-c – Peter Duniho Jun 19 '21 at 18:55
1

Just pass a regular array instead:

var strings = new[] { myString1, myString2 };
new Category(strings);

Then keep the array and change its elements whenever you want.

IS4
  • 11,945
  • 2
  • 47
  • 86
  • Do those more knowledgeable than I think this will work? If so it may be the simplest approach, although StringBuilder and StrWrapper do also. I "get" that strings are immutable. Coming from C/C++, I keep thinking I can just pass a char* around and a reference to that address will get whatever is there now. Or, if you prefer std::string, I could pass a string* around. – Charles Jun 19 '21 at 21:37
  • > You can only assign a new string-reference to that variable, losing the original reference I keep having trouble wrapping my head around this. I *want* to lose the original reference; I want the variable to point to whatever the string content is now. I get that I can't do that. I will use one of these solutions. I just thought I ought to be able to do it with ref, which I see as roughly analogous to & in C/C++. Now that I know I cannot I will quit trying to make it work and move forward. Thanks all! – Charles Jun 19 '21 at 21:37
  • are you sure? I just tried this and definedSets[0] always seems to have the value it had after the constructor was called, not the current value of myString1. – Charles Jun 19 '21 at 23:21