简体   繁体   中英

Why following static function doesn't work ?

Here is my code :

public static class s {

    public static int Dx(this int i, Action<int> act, Func<int, bool> con) {
        if (con(i)) act(i);
        return i;
    }
}

Later In my code I do :

int g = 22;
int false_con = g.Dx(j => j = 11, z => z != 22); // This is 22 which is fine.
int true_con = g.Dx(j => j = 11, z => z == 22);  //This is also 22 which should be 11

How to fix this ?

None of the answers given so far are actual explanations.

A number of the answers given so far state that this happens because int is a value type. Try replacing all the int s with object s in this program. Does it start working the way the original poster expects? No. Then it has nothing to do with value types vs reference types.

Rather, it has to do with the value of a variable , regardless of its type.

Mahdi, your expectation is that formal parameter j becomes an alias for formal parameter i , which is in turn an alias for local variable g , and that therefore any change to j also causes a change to g because they are the same variable. That's not the case. j , i and g are copies of the same value but have different storage locations , so mutating one does not mutate the other.

The way you say "this formal parameter is an alias for this variable" in C# is by using the ref or out keywords. So this program would do what you expect:

delegate void RefAction<T>(ref T t);
...
public static int Dx(ref int i, RefAction<int> act, Func<int, bool> con) 
{
    if (con(i)) 
        act(ref i);
    return i;
}
...
int g = 22;
int false_con = Dx(ref g, (ref int j) => { j = 11; }, z => z != 22); 
int true_con = Dx(ref g, (ref int j) => { j = 11; }, z => z == 22); 

The "ref" keywords mean that g , i , and j are all different names for the same variable.

As D Stanley notes, this is probably bad style. Rather than mutating a variable in a method, instead return the value you want it to be changed to, and let the caller decide what variable to mutate, if any.

Your code path doesn't change as a result of calling the Action , so the program always returns i .

It looks like you expect g to be changed to 11 after the first call, which is not true since the value of g is copied to j and then to i rather than a reference to g , meaning the value at g is not modified as a result of your action.

One option would be to return the value instead of trying to modify it:

public static int Dx(this int i, Func<int, int> act, Func<int, bool> con) {
    if (con(i)) return act(i);
    return i;
}

int g = 22;
g = g.Dx(j => 11, z => z != 22); /* g is still 22 */ 
g = g.Dx(j => 11, z => z == 22);  /* g is now 11 */ 

您的代码返回被调用的整数,因此两种情况均返回g ,即22

You're trying to alter the value of g through the Action<int> act , right?

It won't work as the integer is a primitive type which is passed as value, not as reference, so you're not in fact assigning any value to g.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM