6

Is it possible to use the ref returns feature in C# 7.0 define a generic function that can do both comparison and update of a field in two instances of an Object? I am imagining something like this:

void UpdateIfChanged<TClass, TField>(TClass c1, TClass c2, Func<TClass, TField> getter)
{
    if (!getter(c1).Equals(getter(c2))
    {
        getter(c1) = getter(c2);
    }
}

Example intended usage:

Thing thing1 = new Thing(field1: 0, field2: "foo");
Thing thing2 = new Thing(field1: -5, field2: "foo");
UpdateIfChanged(thing1, thing2, (Thing t) => ref t.field1);
UpdateIfChanged(thing1, thing2, (Thing t) => ref t.field2);

Is there any way to specify a Func type or any kind of generic type restriction that would make this valid by requiring that getter return a reference? I tried Func<TClass, ref TField>, but it doesn't appear to be valid syntax.

2 Answers 2

8

You won't be able to use Func, because it doesn't return the result by reference. You'll need to create a new delegate that uses a ref return:

public delegate ref TResult RefReturningFunc<TParameter, TResult>(TParameter param);

Then changing your function to use that delegate is enough for it to work:

public static void UpdateIfChanged<TClass, TField>(TClass c1, TClass c2, RefReturningFunc<TClass, TField> getter)
{
    if (!getter(c1).Equals(getter(c2)))
    {
        getter(c1) = getter(c2);
    }
}

Note that a property cannot be returned by reference. You could return a field by reference, or any other variable, but a property is not a variable.

Sign up to request clarification or add additional context in comments.

Comments

5

You need to declare your own delegate type for it. For example:

using System;

public class Thing
{
    public int field1;
    public string field2;    
}

public delegate ref TOutput FuncRef<TInput, TOutput>(TInput input);

public class Test
{
    public static void Main()
    {
        Thing thing1 = new Thing { field1 = 0, field2 = "foo" };
        Thing thing2 = new Thing { field1 = -5, field2= "foo" };
        UpdateIfChanged(thing1, thing2, (Thing t) => ref t.field1);
        UpdateIfChanged(thing1, thing2, (Thing t) => ref t.field2);
    }

    static void UpdateIfChanged<TInput, TOutput>(TInput c1, TInput c2, FuncRef<TInput, TOutput> getter)
    {
        if (!getter(c1).Equals(getter(c2)))
        {
            getter(c1) = getter(c2);
        }
    }
}

(Note the use of "field" instead of "property" everywhere.)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.