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?

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).


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.


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.


27

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


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.


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()

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());
    }  
}

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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.