if s1 is passed by reference to Func(), then why does
myString.Append("test") does change it
Its not passed by references, instead its address value is passed to the function.
Suppose S1 is pointing to a memory location 0x48, This will be passed to Func, where Func parameter myString will start pointing to that location. Later when you Append a text to that location, it gets added. But later when you assign null to myString, it starts pointing to nothing, but the original location remains unchanged.
You should see: Parameter passing in C# by Jon Skeet
Consider the following diagrams.
In Step 1, you create a new object of type StringBuilder and let S1 refers to that object.

In Step 2, after passing S1 to Func, now myString also points to the same object in memory.

Later when you Append, text through myString, it updates the original object, since myString is pointing to the memory location held by the object.
In Step 3, when you assign null to the myString it looses the address for StringBuilder object, but this doesn't change anything in the object or the pointer S1.
