Delegat Func bez typu zwrotu

561

Wszyscy delegaci Func zwracają wartość. Jakich delegatów .NET można używać z metodami, które zwracają wartość void?

Marcel Lamothe
źródło

Odpowiedzi:

759

Wszyscy delegaci Func zwracają coś; wszyscy delegaci akcji zwracają nieważność.

Func<TResult> nie przyjmuje argumentów i zwraca TResult:

public delegate TResult Func<TResult>()

Action<T> pobiera jeden argument i nie zwraca wartości:

public delegate void Action<T>(T obj)

Action jest najprostszym „nagim” delegatem:

public delegate void Action()

Są też Func<TArg1, TResult>i Action<TArg1, TArg2>(i inne do 16 argumentów). Wszystkie te (z wyjątkiem Action<T>) są nowe w .NET 3.5 (zdefiniowane w System.Core).

Jason
źródło
11
Do Twojej wiadomości, następna wersja biblioteki klas podstawowych będzie zawierać typy Func i Action, które obsługują więcej niż cztery parametry formalne. Nie pamiętam dokładnie, jak duże są.
Eric Lippert
88
W .NET 4.0 przechodzą teraz do 8 parametrów. Jeśli tak utrzymają, w następnej wersji wzrośnie do jedenastej !! 11 !!!
Michiel van Oosterhout
9
W rzeczywistości wygląda na to, że osiągają 16 w 4.0.
Tustin2121
7
1, 4, 16, 64, 256, 1024, 4096, 16384, 65536, ... to wyraźnie wskazuje, że kompilator będzie w stanie poradzić sobie z większą liczbą argumentów funkcji niż obecnie w przyszłości !
Chris Morgan
6
Właściwie Tustin2121 ma rację, poszli do 16 parametrów (plus typ zwrotu w przypadku Func<,,, ... ,>) w .NET 4.0, ale ostatnie osiem typów każdej „serii” jest zdefiniowane w System.Core.dll, a nie w mscorlib.dll, więc to byłby powód dlaczego Michielvoo ich nie widział. Jednak w wersjach .NET 4.5 i 4.5.1 nie dodano żadnych funcs ani akcji. Czy ta sekwencja stanie się A170836 lub A170875 ? Bądźcie czujni.
Jeppe Stig Nielsen
83

... nie przyjmuje argumentów i ma typ nieważnego zwrotu?

Uważam, że Actionjest to rozwiązanie.

Marcel Lamothe
źródło
47

Wszyscy delegaci Func biorą co najmniej jeden parametr

To nieprawda. Wszystkie pobierają co najmniej jeden argument typu, ale ten argument określa typ zwracany.

Dlatego Func<T>nie przyjmuje żadnych parametrów i zwraca wartość. Użyj Actionlub, Action<T>gdy nie chcesz zwracać wartości.

Joel Coehoorn
źródło
27

Spróbuj System.Func<T>iSystem.Action

JaredPar
źródło
1
Nie sądzę jednak, że 0 arg i coś, co nie istnieje w .Net 2.0.
Brian
1
To dziwne: Func w ogóle nie istnieje w .Net 2.0, chociaż Predicate i Action tak.
Joel Coehoorn
2
W przypadku platformy .NET 2.0 użyj delegata MethodInvoker.
Trevor Elliott,
.NET 2 miał także (lub ma) typ delegata, Converter<TInput, TOutput>który był podobny do późniejszego Func<T, TResult>. Został użyty w List<>.ConvertAllmetodzie, która rzutowała każdy element List<>na inny obiekt i umieściła wszystkie „wartości funkcji” w nowym List<>. (Później często używa się Selectdo tego Linq .)
Jeppe Stig Nielsen
0

Czasami będziesz chciał napisać delegata do obsługi zdarzeń, w którym to przypadku możesz skorzystać, System.EvenHandler<T>który domyślnie akceptuje argument typu objectoprócz drugiego parametru, który powinien pochodzić EventArgs. EventHandlers powrócąvoid

Osobiście uznałem to za przydatne podczas testowania do utworzenia jednorazowego wywołania zwrotnego w ciele funkcji.

AndyG
źródło
0

... nie przyjmuje argumentów i ma typ nieważnego zwrotu?

Jeśli piszesz System.Windows.Forms, możesz również użyć:

public delegate void MethodInvoker()
mojmir.novak
źródło
0

Bardzo łatwy sposób na wywołanie podprogramów wartości zwracanej i wartości nie zwracającej. używa odpowiednio Func i Action . (patrz także https://msdn.microsoft.com/en-us/library/018hxwa8(v=vs.110).aspx )

Wypróbuj ten przykład

using System;

public class Program
{
    private Func<string,string> FunctionPTR = null;  
    private Func<string,string, string> FunctionPTR1 = null;  
    private Action<object> ProcedurePTR = null; 



    private string Display(string message)  
    {  
        Console.WriteLine(message);  
        return null;  
    }  

    private string Display(string message1,string message2)  
    {  
        Console.WriteLine(message1);  
        Console.WriteLine(message2);  
        return null;  
    }  

    public void ObjectProcess(object param)
    {
        if (param == null)
        {
            throw new ArgumentNullException("Parameter is null or missing");
        }
        else 
        {
            Console.WriteLine("Object is valid");
        }
    }


    public void Main(string[] args)  
    {  
        FunctionPTR = Display;  
        FunctionPTR1= Display;  
        ProcedurePTR = ObjectProcess;
        FunctionPTR("Welcome to function pointer sample.");  
        FunctionPTR1("Welcome","This is function pointer sample");   
        ProcedurePTR(new object());
    }  
}
Aarón Ibañez Werthermänn
źródło
1
Dziękujemy za ten fragment kodu, który może zapewnić pewną ograniczoną, natychmiastową pomoc. Właściwe wyjaśnienie byłoby znacznie poprawić swoją długoterminową wartość pokazując dlaczego jest to dobre rozwiązanie problemu, a byłoby bardziej użyteczne dla czytelników przyszłości z innymi, podobnymi pytaniami. Proszę edytować swoją odpowiedź dodać kilka wyjaśnień, w tym założeń już wykonanych.
iBug