Passing properties by reference in C#
Properties cannot be passed by reference. Here are a few ways you can work around this limitation.
1. Return Value
string GetString(string input, string output)
{
if (!string.IsNullOrEmpty(input))
{
return input;
}
return output;
}
void Main()
{
var person = new Person();
person.Name = GetString("test", person.Name);
Debug.Assert(person.Name == "test");
}
2. Delegate
void GetString(string input, Action<string> setOutput)
{
if (!string.IsNullOrEmpty(input))
{
setOutput(input);
}
}
void Main()
{
var person = new Person();
GetString("test", value => person.Name = value);
Debug.Assert(person.Name == "test");
}
3. LINQ Expression
void GetString<T>(string input, T target, Expression<Func<T, string>> outExpr)
{
if (!string.IsNullOrEmpty(input))
{
var expr = (MemberExpression) outExpr.Body;
var prop = (PropertyInfo) expr.Member;
prop.SetValue(target, input, null);
}
}
void Main()
{
var person = new Person();
GetString("test", person, x => x.Name);
Debug.Assert(person.Name == "test");
}
4. Reflection
void GetString(string input, object target, string propertyName)
{
if (!string.IsNullOrEmpty(input))
{
var prop = target.GetType().GetProperty(propertyName);
prop.SetValue(target, input);
}
}
void Main()
{
var person = new Person();
GetString("test", person, nameof(Person.Name));
Debug.Assert(person.Name == "test");
}
how to pass a property by reference in C#
You could write an ugly extension method that takes an expression representative of the property you want to set, and give it a chance to check whether your new values are null
or empty (or different from the destination) before assigning the value.
public static void SetPropertyValue<T>(this T target, Expression<Func<T, string>> memberLamda, string value)
{
// Check if "new value" is null or empty and bail if so
if (string.IsNullOrEmpty(value))
return;
var memberSelectorExpression = memberLamda.Body as MemberExpression;
if (memberSelectorExpression != null)
{
var property = memberSelectorExpression.Member as PropertyInfo;
if (property != null)
{
// Get the existing value and compare against the new value
// Only set the property if it's different from the existing value
if ((string)property.GetValue(target, null) != value)
{
property.SetValue(target, value, null);
}
}
}
}
Source
And then you could use it like:
anObject.SetPropertyValue(a => a.SampleText1, value1);
anObject.SetPropertyValue(a => a.SampleText2, value2);
This should allow you to avoid having the object marked as "dirty", but is rather expensive (as Marc mentioned in a comment on his answer).
C# Properties as Reference
No, properties that are passed into methods are not modified in that method, because you cannot pass them by reference. Properties are always passed by value, so you cannot change their value within the methods that you pass them two.
However, that's not actually what you are doing in both methods, and that's why one works and one does not.
Your first method:
public void ChangeCountry(string _Country)
{
_Country = "US";
}
attempts to change the value of the parameter that does not have the ref
keyword, which fails (as you noted).
Your second method,
public void ChangeAddress(Address _adr)
{
_adr.Country = "US";
}
is not trying to change the value of its parameter. The Address
object that you pass into the method remains the same instance of Address
for the entire method. However, because Address
is a reference type, you can change its properties, and those changes will persist once the method returns. They will also be visible to any other places that have a reference to the same instance.
To see the difference, if you had tried to do this in your second method, it would have failed, for the same reason your first method does:
public void ChangeAddress(Address _adr)
{
_adr = new Address();
_adr.Country = "US";
}
Here, you are trying to change the value of the parameter -- to a new instance of the class -- and that doesn't work without the ref
keyword.
Is it possible to pass a property as a ref parameter in a setter? c# (avoid a property or indexer may not be passed as an out or ref parameter .)
No, basically.
There is a potential loophole around mutable ref-returning get-only properties, but that probably won't help you because:
- you can't have any set logic in a mutable ref-returning get-only property
- this is an absurdly niche scenario that the majority of devs don't know exists, and will never need to use :)
C# Pass a property by reference
You can call the function with a lambda expression:
private void setFromQueryString<T>(Action<T> setter, String queryString, HttpContext context)
{
//here I want to handle pulling the values out of
//the query string and parsing them or setting them
//to null or empty string...
String valueString = context.Request.QueryString[queryString].ToString();
//I need to check the type of the property that I am setting.
//this is null so I can't check it's type
Type t = typeof(T);
...
setter(value);
}
You would call it like this:
setFromQueryString<int>(i => myFoo.Age = i, "inputAge", context);
EDIT: If you really want type inference:
private void setFromQueryString<T>(Func<T> getter, Action<T> setter, String queryString, HttpContext context) {
...
}
setFromQueryString(() => myFoo.Age, i => myFoo.Age = i, "inputAge", context);
c# pass property backing value by reference, is it possible?
There is no valid identifier for the backing field for that property. You could not use an auto property, and instead explicitly define the get
and set
methods of the property, along with your own backing field, thus giving you a valid identifier for the backing field, although it would be very poor design to expose this backing field externally.
What you should do is re-design your code such that you don't need to pass the value by reference in the first place. You should just be passing the string by value and, if the result of this function is the computation of a string, returning it. The caller can then set that string back to the property if that's what they want. That would be the more idiomatic design. (Since you also have a boolean value you'd need to pass both the string and the boolean out, of course.)
Are properties passed by reference in C#?
You need to use the ref
keyword to pass by reference in C#. In C#, pass by value is the default. This is a little confusing when you pass a non-immutable class instance, because what you're passing is the value of a reference. When you pass a class reference to a method, without the ref
keyword, the method can change the properties of the instance, but they can't change the caller's reference to that instance. They can't change the caller's reference to refer to a new instance. But with ref
(or out
), they can.
The ref
keyword in C# can't be used with a property. See fiddle for the code below:
Compilation error (line 8, col 15): A property, indexer or dynamic member access may not be passed as an out or ref parameter
C#
using System;
public class Program
{
public static void Main()
{
var c = new C();
F(ref c.P);
}
public static void F(ref int n) { }
public class C
{
public int P { get; set; }
}
}
This is because ref int
is a reference to an int, and a property with a getter and a setter is not an integer. It's code that returns an integer, or can have an integer assigned to it. C# does some magic, but not that much magic. And "magic" is just code generated by the compiler. They could have done that. But they didn't.
I would guess that they wanted to keep it as simple syntactic sugar on a pointer (or whatever thing closely analogous to it) for the sake of runtime efficiency. But that guess could be hilariously wrong.
Is it possible to pass properties as out or ref parameters?
Apologies for the short answer, but no, the C# language specification disallows it.
See this answer to another question to see what happens when you try.
It also says why you shouldn't make the property just be a public field to get around the restriction.
Hope this helps
EDIT: You ask Why?
You pass a variable to an out
or ref
parameter you're actually passing the address (or location in memory) of the variable.
Inside the function the compiler knows where the variable really is, and gets and writes values to that address.
A property looks like a value, buts it's actually a pair of functions, each with a different signature. So to pass a property, you'd actually need to pass two function pointers, one for the get, and one for the set.
Thats a completely different thing to pass to a function than the address of a variable
i.e. one variable address v's two function pointers.
Update
Why doesn't C# just look after this for us?
I'm no Eric Lippert, but I'll have a go at why
What should the signature of the function you're calling be?
Lets say you want to call void MyFn(ref int i)
should that remain that way, or should it change to say we also allow properties? If it changes to some syntax like void MyFn(prop_ref int i)
then this is fairly useless, you can't pass properties to library functions or 3rd party code that wasn't written with the special prop_ref modifier. Anyway I think you're suggesting it shouldn't be different.
Now lets say MyFn
passes i
to a COM function, or WinAPI call, passing the address of i
(i.e. outside .net, by ref). If it's a property, how do you get the address of i
? There may be no actual int under the property to get the address of. Do you do what VB.Net does?
The Vb.Net compiler spots when a property is passed as a ByRef argument to a method. At that point it declares a variable, copies the property to the variable, passes the variable byref and then after the method is called, copies the variable back into the property. i.e.
MyFunc(myObject.IntProperty)
becomes
Dim temp_i As Integer = myObject.IntProperty
MyFunc(temp_i)
myObject.IntProperty = temp_i
Any property side effects don't happen until MyFunc
returns, which can cause all sorts of problems and lead to very subtle bugs.
In my humble opinion the Vb.Net solution to this problem is also broken, so I'm not going to accept that as an answer.
How do you think the C# compiler should handle this?
Related Topics
Launching an Application (.Exe) from C#
Reading Email Using Pop3 in C#
Why Are C# 3.0 Object Initializer Constructor Parentheses Optional
Why Is It Bad to Use an Iteration Variable in a Lambda Expression
C# Splitting Strings on '#' Character
How to Get the Full Path of Running Process
How to Get Windows Display Settings
C# Switch Statement Limitations - Why
Open Existing File, Append a Single Line
Reading 64Bit Registry from a 32Bit Application
Easiest Way to Parse JSON Response
Create Folder and File on Current User Profile, from Admin Profile
Mono High Resolution Timer (On Linux)