Autor Wątek: C# Delegat -dostęp  (Przeczytany 2671 razy)

Offline jerryharpman

  • Użytkownik

# Luty 03, 2016, 13:23:39
Przedstawię to obrazowo:
klasa{
zmienna
delegat()
}

funkcja_delegata();

czy chcąc uzyskać dostęp do "zmiennej" klasy w "funkcji_delegata" muszę ją przekazywać jako parametr funkcji ?
Czy można to jakoś obejść ? Bo przy większej klasie robi się tego sporo do przekazania.

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline Ajgor

  • Użytkownik

# Luty 03, 2016, 14:56:24
Tak. Przez parametr. Delegat musi mieć parametr ego samego typu co funkcja i przekazujesz przez parametr delegata. Może, jak masz dużo do przekazania, spróbuj może stworzyć strukturę? Albo, jeśli dane są tego samego typu, to tablicę?

Offline deadeye

  • Użytkownik

# Luty 03, 2016, 15:01:08
możesz przekazać te zmienne, możesz przekazać całą klasę która wywołuje delegata (i mieć dostęp do jej zmiennych publicznych), albo jeśli to ma sens, zrobić typ który agreguje więcej niż jedną zmienną jako return value, i po wywołaniu delegata przepisać te zmienne do klasy wywołującej.

Offline Kos

  • Użytkownik
    • kos.gd

  • +2
# Luty 03, 2016, 16:47:08
Er, nie wiem czy dobrze rozumiem problem, ale nie możesz sobie wziąć w domknięcie tego co potrzebujesz?
http://stackoverflow.com/questions/428617/what-are-closures-in-net ?

Offline jerryharpman

  • Użytkownik

# Luty 03, 2016, 17:55:51
Domknięcie to chyba nie to czego potrzebuje.
Wyjaśnię to dokładniej :
public class Klasa
{
//obiekty tej klasy różnią się funkcją Init()
public int zmienna;
public delegate bool Init(int i);
public Init init;
}

public class Klasa2
{
//zawiera zbiór funkcji dla Init()
public bool Funkcja1(int i)
{
i++;
return true;
}

public bool Funkcja2(int i)
{
i--;
return true;
}
}

public class Test
{
// przykładowa klasa, żeby pokazać przypisanie funkcji
Klasa2 funkcje = new Klasa2();
Klasa obiekt1 = new Klasa();
Klasa obiekt2 = new Klasa();

public void test()
{
obiekt1.init = funkcje.Funkcja1;
obiekt2.init = funkcje.Funkcja2;
                obiekt1.init(obiekt1.zmienna);
}
}

Jak widać funkcje przypisywane delegatem operują na zmiennych z nieswojej klasy. Przekazuję je więc parametrami.
Ciekawi mnie czy da się to zrobić tak, żeby np Funkcja1 miała dostęp do Klasa.zmienna bez przekazywania czegokolwiek w parametrach.

Offline koirat

  • Użytkownik

  • +1
# Luty 03, 2016, 18:10:29
Możesz agregować w Klasie2 zmienną typu Klasa wtedy Funkcja1 będzie miała dostęp do "zmienna"
Możesz uczynić Klasa statyczną lub zmienną statyczną i wtedy również będziesz miał dostęp do "zmienna"

Ale może lepiej powiedz co chcesz zrobić, bo w tym momencie to co chcesz osiągnąć  zdaje się  być brudnym hackiem.

Offline jerryharpman

  • Użytkownik

# Luty 03, 2016, 18:27:08
Od razu hack :p
Zrobiłem taki system skilli w grze.
"Gracz" posiada List<Skill>
"Skill" posiada List<IntParams>, List<FloatParams>, List<BoolParams> oraz funkcję obsługi skilla (delegat).
Przy tworzeniu nowego Skilla dodaję mu nową funkcję przez delegat a przy używaniu tej funkcji przekazuję parametry Skilla (skille używają różnych parametrów w różny sposób, więc użyłem te 3 listy)

Muszę przemyśleć tę agregację, bo to może być to czego chcę.
No nie wpadłem na lepszy pomysł zaprojektowania skilli, chętnie posłucham jak wy byście to zrobili. (pracuję w Unity jak coś)

Offline koirat

  • Użytkownik

  • +2
# Luty 03, 2016, 18:52:33
Zamień List<Skill>  na interfejs List<ISkill>

interface ISkill{
       bool CanExecute(owner);
       void Execute(owner,targets[]);
}

Teraz Każdy skill powinien dziedziczyć po ISkill;

Np taki skill z delegatami możesz sobie wykonać tak:


class DelegatedSkill:ISkill{

      Func<owner,bool> CanExecuteFunc{get;set;}
      Func<owner,targets[]> ExecuteFunc{get;set;}

      public DelegatedSkill(Func<owner,bool> canExecuteFunc, Func<owner,targets[]> executeFunc){
              CanExecuteFunc = canExecuteFunc;
              ExecuteFunc = executeFunc;
     }

       public bool CanExecute(owner){
                  return CanExecuteFunc(owner);
       }
       public void Execute(owner,targets[]){
                  ExecuteFunc(owner,targets);
       }

}



Jak widzisz owner i targets nie mają typu bo musisz sobie jakiś wymyślić.
« Ostatnia zmiana: Luty 03, 2016, 18:55:08 wysłana przez koirat »

Offline jerryharpman

  • Użytkownik

# Luty 03, 2016, 20:22:25
koirat nic nie ułatwileś chyba...
z tego co widzę to CanExecute nie musi przyjmować tego parametru bo ma do niego dostęp po dziedziczeniu, ale wewnątrz nadal musisz go przekazać do CanExecuteFunc, czyli na jedno mi wychodzi

problemem jest dostęp funkcji delegata do klasy w której ma działać, ale najwyraźniej nie da się tego zrobić tak jak chciałem bo nie ma dostępu "do góry" tylko "w dół". ot takie ograniczenie językowe chyba.
(a oficjalne źródła unity proponują "zaboxować" dane w typie Object i ustawic hierarchie xD ta, jasne... wole przekazywać parametry )

Offline koirat

  • Użytkownik

# Luty 03, 2016, 21:13:02
Liźnij trochę programowania i powróć do tego wątku za rok, zobaczysz o co biega. Człowiek dość szybko uczy się na błędach, trzymam kciuki.

Offline topik92

  • Użytkownik

# Luty 11, 2017, 23:33:42
To co próbujesz zrobić możesz osiągnąć stosując curring, i nie będzie to brudny hak. Chodzi o to że początkowo podajesz funkcje która ma dodatkowy parametr dla brakującej zmiennej, a potem przekształcasz ją w taką co ma ten parametr ustawionym na sztywno i nie trzeba go podawać. Ponieważ korzystasz z domknięcia to zmienna zawsze będzie aktualna.
   
class MyClass
    {
        private int zmienna;
        public MyClass(Func<object,int,int> delegata)
        {
            Delegata = (o) => delegata(o, zmienna); /*robisz curring i twoja zmienna będzie domyślnie przekazywana*/
        }
        public Func<object, int> Delegata { get; private set; }// przy korzystaniu podajesz tylko jeden  parametr
   a zmienna jest przekazywana automatycznie
}

Możesz jeszcze zrobić tak, ale to trochę hak :P
        class KlasaA
        {
            private int privVariable = 0;

            public class FriendOfA : FriendAssesHack<KlasaA>
            {
                public FriendOfA(KlasaA friend) : base(friend)
                {
                }
                public void DoSometing() // ta-dam! masz dostęp do innej klasy
                {
                    friend.privVariable++;
                }
            }
        }
        class FriendAssesHack<TtargerClass>
        {
            protected readonly TtargerClass friend;
            public FriendAssesHack(TtargerClass friend)
            {
                this.friend = friend;
            }
        }
« Ostatnia zmiana: Luty 12, 2017, 00:02:59 wysłana przez topik92 »