[C#] Typ jako argument funkcji

Witam

Chciałbym stworzyć pewną funkcję. Poglądowo wygląda ona tak

void CheckControls(ControlCollection kontrolki, Type typ, Function funkcja)

{

	foreach(Control c in kontrolki)

	{

		if(c is typ)

		{

			funkcja(c);

		}

		if(c.HasChildren)

		{

			CheckControls(c.Controls);

		}

	}

}

Jednak aktualnie nie wiem jak użyć funkcji jako argumentu innej funkcji i jak użyć typu jako argument funkcji.

Generalnie musisz poczytać o delegatach. Pełnią one w .NET rolę wskaźników do funkcji. Poniżej przykład użycia:

using System;


namespace ConsoleApplication1

{

    public delegate void MyFunctionDelegate(SomeClass someClass);


    public class SomeClass

    {

        public string someString;


        public SomeClass(string someString)

        {

            this.someString = someString;

        }

    }


    public class SomeClass1 : SomeClass

    {

        public SomeClass1()

            : base("SomeClass 1")

        { }

    }


    public class SomeClass2 : SomeClass

    {

        public SomeClass2()

            : base("SomeClass 2")

        { }

    }


    class Program

    {

        public static void MyFunction(SomeClass someClass)

        {

            Console.WriteLine(someClass.someString);

        }


        public static void SomeFunction(object o, MyFunctionDelegate d)

        {

            if (typeof(SomeClass1).IsInstanceOfType(o))

                d((SomeClass1)o);

            else

                d((SomeClass2)o);

        }


        static void Main(string[] args)

        {

            MyFunctionDelegate d = new MyFunctionDelegate(MyFunction);


            SomeFunction(new SomeClass1(), d);

            SomeFunction(new SomeClass2(), d);

            SomeFunction(new SomeClass1(), d);


            Console.ReadKey();

        }

    }

}

Temat jest zupełnie nietrafiony. Powinien brzmieć [C#] funkcja jako argument funkcji oraz porównywanie typów obiektów.

EDIT: Trochę rozbudowałem przykład :slight_smile:

Kiedy on nie chce porównywać typów obiektów, lecz przekazać typ jako argument.

Sugerowałbym użyć metody generycznej zamiast podawać typ wśród argumentów.

void CheckControls(Control.ControlCollection collection)

{

    foreach (Control c in collection)

    {

        if (c is T)

        {

            MessageBox.Show("Znalazłem!");

        }

        if (c.HasChildren)

        {

            CheckControls(c.Controls);

        }

    }

}

A co tak w ogóle chcesz osiągnąć? Bo na pierwszy rzut oka bez sensu jest wywoływanie metody jednocześnie z typem i zależnym od niego delegatem na metodę do wykonania. Nie lepiej byłoby skojarzyć typy z metodami w słowniku?

Szczerze mówiąc jedynie mi chodziło o to żeby np. wszystkie TextBoxy ukryć. Do tego potrzebowałem rekurencji (GroupBoxy, SplitContaintery itp) w połączeniu ze sprawdzaniem typu. A to z funkcją tak na momencie w trakcie zakładania tematu mi wpadło. Właśnie w takim celu jak wyżej wymieniłem

wszystkie(this.Controls, TextBox, ukryj).

Wiem, że to można by zrobić na zasadzie

ukryj(TextBox).

Ale jak mówię, to mi w chwili pisania tematu wpadło i z ciekawości to zostawiłem bo próbowałem przesłać funkcję jako argument i nie mogłem a teraz przynajmniej wiem gdzie szukać.

@somekind

Pytanie, które postawił autor tematu jest błędne, ale to co chciał osiągnąć da się odczytać z wrzuconego przez niego kodu. Mam na myśli linijki if(c is typ) oraz Funkcja funkcja. Kod, który wrzuciłem jest jak najbardziej wystarczający, aby rozwiązać oba te problemy.

Z tego, co rozumiem, to chcesz to robić odwrotnie niż należy. Nie ma sensu pisanie uniwersalnej funkcji, a potem przekazywanie do niej jako argumentu funkcji, którą tamta funkcja ma wykonać. :wink:

Funkcja powinna robić jedną, konkretną rzecz. Jeśli chcesz ukrywać kontrolki danego typu, to napisz po prostu funkcję, która ukrywa kontrolki, np.:

void HideControls(Control.ControlCollection collection)

{

    foreach (Control c in collection)

    {

        if (c is T)

        {

            c.Hide();

        }

        if (c.HasChildren)

        {

            HideControls(c.Controls);

        }

    }

}

Użycie:

this.HideControls(this.Controls);

Jeśli zachodzi potrzeba przekazania typu do funkcji, naturalnym i oczywistym wyborem wydają się metody generyczne. Dlatego, bo poza ładnym rozwiązaniem problemu pozwalają na nałożenie wymuszeń co do przekazywanych typów (klauzula where) i umożliwiają zabezpieczenie się przed błędami niezgodności typów już w czasie kompilacji. Jest to lepsze niż rozwiązanie w teorii oparte na typeof i is, a w praktyce na InvalidCastException i InvalidOperationException.

Co masz przeciwko metodom generycznym?

Nic, bo sam ich używam. Skąd pomysł, że mam coś przeciwko nim -,-? Mam wrażenie, że rozmawiamy o dwóch różnych rzeczach. Ja skupiłem się na kodzie, który wrzucił autor tematu, a Ty na samym tytule tematu

i stąd nieporozumienie. Zakończmy tą dyskusję, bo jest bezproduktywna.

No właśnie ja też. ;]

Skorzystaj z możliwości jakie daje .NET Framework 3.5 i uzupełnij klasę kolekcji o nową metodę:

public static class ExtensionMethods

{

  public static IEnumerable AllChildControls(this Control instance)

  {

    foreach (Control control in instance.Controls)

    {

      yield return control;

      foreach (Control child in control.AllChildControls())

      {

        yield return child;

      }

    }

  }

}

Z nowej metody będziesz mógł skorzystać tak:

this.AllChildControls().OfType().ToList().ForEach(c => c.Hide());

Jeśli już robić metodę rozszerzającą, to może od razu taką, która od razu zwróci kontrolki oczekiwanego typu.