Wie kann ich Parameter in C# "out" machen?

Wie kann ich Parameter in C# "out" machen?

Sie können die Argumente nicht als out behandeln lassen (oder ref ) und verwenden Sie den params Funktion gleichzeitig. Es funktioniert einfach nicht. Das Beste, was Sie tun können, ist, einen Array-Parameter zu erstellen, das Array zu erstellen out , deklarieren Sie eine Array-Variable und rufen Sie die Methode auf, die das Array übergibt, und untersuchen Sie dann jedes Element manuell anhand des Index.

Foo(out object[] data) {...}
object[] result;
Foo(out result);
// look at result[0], result[1], result[2] etc

Also:Sie können nicht was du willst. Selbst wenn du könntest, ref / out nie funktionieren, es sei denn, es gibt eine genaue Übereinstimmung zwischen den Datentypen, also würde es noch muss sein:

object o1, o2, o3, o4;
Foo(out o1, out o2, out o3, out o4);
// cast o1, o2, o3, o4

Was immer noch nicht das ist, was Sie wollen.


Es besteht keine technische Notwendigkeit für out hier. Das funktioniert:

void Fill(object[] p)
{
    p[0] = 1;
    p[1] = 42;
    p[2] = "Hello";
    p[3] = -1;
    p[4] = "World";
}

object[] p = new object[5];
foo.Fill(p);
i = (int)p[0];
i2 = (int)p[1];
sz = (string)p[2];
i3 = (int)p[3];
sz2 = (string)p[4];

Sie könnten Ihre Werte als Tuple zurückgeben:
(definieren Sie Ihre eigene Tupelklasse, wenn Sie nicht .NET4.0 verwenden)

static Tuple<int, string> Fill()
{
    return new Tuple(42, "Hello World");
}

und definieren Sie dann Erweiterungsmethoden zum Entpacken von Tupeln:

public static class TupleExtensions
{
    public static void Unpack<T1, T2>(
        this Tuple<T1, T2> tuple,
        out T1 item1,
        out T2 item2)
    {
        item1 = tuple.Item1;
        item2 = tuple.Item2;
    }
}

Dann können Sie Folgendes schreiben:

int i;
string sz;

foo.Fill().Unpack(out i, out sz);

1) Wenn Sie die Notwendigkeit vermeiden können, die Werte in deklarierten Variablen zu erhalten, dann ist das Übergeben des Arrays und Füllen die beste Option, wie die Antwort von dtb zeigt.

2) Andernfalls können Sie einen einfachen Wrapper für Ihre Variable haben.

public class Wrapper //or may be generic?
{
    public object Value { get; set; }

    public Wrapper(object value)
    {
        Value = value;
    }
}

Jetzt können Sie

anrufen
var i = new Wrapper(0), i2 = new Wrapper(0), i3 = new Wrapper(0);
c.Fill(i, i2, i3);
i.Value //your value here

public static void Fill(this SomeClass c, params Wrapper[] p)
{
    for (int i = 0; i < p.Length; i++)
    {
        p[i].Value = 1; //assigning
    }
}

Sie müssen sich mit Value befassen -Eigenschaft nach dem Aufruf von Fill Methode.

3) Sie können den Verschluss verwenden. So etwas wie Ref<T> Klasse wie gezeigt implementiert:

public static class Ref
{
    public static Ref<T>[] Create<T>(params Expression<Func<T>>[] getters)
    {
        return getters.Select(Create).ToArray();
    }

    public static Ref<T> Create<T>(Expression<Func<T>> getter)
    {
        return new Ref<T>(getter);
    }
}

public sealed class Ref<T>
{
    readonly Func<T> getter;
    readonly Action<T> setter;

    public Ref(Expression<Func<T>> getter)
    {
        var output = getter.Body;
        var input = Expression.Parameter(output.Type); //or hardcode typeof(T)
        var assign = Expression.Assign(output, input);
        var setter = Expression.Lambda<Action<T>>(assign, input);

        this.getter = getter.Compile();
        this.setter = setter.Compile();
    }

    public T Value
    {
        get { return getter(); }
        set { setter(value); }
    }
}

public static void Fill(this SomeClass c, params Ref<object>[] p)
//assign inside

object i = 0, i2 = 0, i3 = 0;
c.Fill(Ref.Create(() => i, () => i2, () => i3));
//i, i2 etc changed

Einige Dinge zu beachten:

  1. Alle oben genannten Ansätze sind im Grunde ref Ansätze erzwingt der Compiler nicht einfach die Zuweisung von Parameterwerten innerhalb der Methode, bevor das Steuerelement verlässt, wie im Fall von out Das ist Ihre Frage, aber soweit ich weiß out ist hier nicht möglich.

  2. Ich mag den ersten, einfach und konventionell . Wenn dies nicht möglich ist, stimme ich für den 3. Ansatz.

  3. Wie andere bereits erwähnt haben, können Sie nur genau denselben Typ wie ref/out übergeben Parameter. Also, wenn Ihre Methode per Definition willkürliche Referenzen von object verwendet Typ, müssen Sie sogar Ihre Variablen als object deklarieren örtlich. Im letzten Ansatz können Sie das Ganze generisch machen, indem Sie den Parametertyp auf Ref<T> ändern ab Ref<object> aber das bedeutet, dass alle lokalen Variablen auch ein T sein sollten .

  4. Sie können eine Wörterbuchstruktur verwenden, um Ref<T> zwischenzuspeichern um zu vermeiden, dass dieselben Bäume erneut kompiliert werden.

  5. Dieselbe Implementierung kann verwendet werden, um Eigenschaften und Variablen als Methodenargumente zu übergeben oder Werte per Referenz zurückzugeben.