C#, const dla parametrów funkcji ?

0

Jak radzicie sobie z niemożnością użycia słowa kluczowego const podczas przekazywania parametrów do funkcji (w taki sposób w jaki można to wykonać w c++) ?

0

Bardzo łatwo. Nie widzę do czego miało by mi to być potrzebne.
Napisz może o co Ci chodzi, co chcesz tym osiągnąć?

0

Czasem użyteczne jest zagwarantowanie, że dany argument przekazany do funkcji nie zostanie zmieniony. Albo zagwarantowanie, że dana metoda nie zmieni pól obiektu. W c++ można to było osiągnąć poprzez użycie słowa "const". W C# nie widzę takiej możliwości ?

1

ogolnie się nie da. Jest obejscie problemu... ale nie warto

http://stackoverflow.com/questions/3799062/const-methods-in-c-sharp

pamietaj C# to nie C++. Nie przenos ideologii jednego jezyka na drugi. Przewaznie to nie dziala.

0

A może by tak zrobić deep copy tego co chcesz przekazać przed wywołaniem, albo nawet to w extensiona opakować.

0

w C# nie ma idei "const correctness". const używa się rzadko, do definiowania stałych.

0

OK, to teraz taka sytuacja. Metoda zwraca jakiś obiekt. Ale chcę, żeby nikt mi tego obiektu nie zmienił (w c++ to jest zwracanie stałej referencji). W C# jedyną opcją jest zwrócenie kopii tego obiektu?

0

Obiekty anonimowe są całkowicie readonly, więc w tę stronę można iść jak się musi.

6

To nie jest jakiś duży problem, bo:

  1. W przypadku typów wartościowych takie zachowanie jest domyślne. Żeby móc zmienić w metodzie wartość parametru tak, aby była widziana poza nią, należałoby przekazać go jako out lub ref.
  2. W przypadku typów referencyjnych w metodzie nie podmienisz obiektu (no chyba, że użyjesz out albo ref).
  3. Jeśli o pola typów referencyjnych chodzi, to wystarczy, żeby klasa nie dawała możliwości zmiany takich pól.

Reasumując - aby osiągnąć to, czego potrzebujesz - wystarczy tak definiować klasy, aby obiekt po utworzeniu był niezmienny, oraz nie używać out i ref.

P.S. Stosowanie ref i out to w ogólności okropna praktyka prowadząca do powstawania syfiastego kodu.

1

Ale chcę, żeby nikt mi tego obiektu nie zmienił

No cóż, w C# nie ma takiej obsesji w której programista broni się przed samym sobą, i pisząc funkcję foo() nie ufa sobie piszącemu funkcję bar() ;-)

0

Przekazując do funkcji argument int[,] zapomnialem, ze to przeciez typ referencyjny! Przypisujac wiec wartosci do poszczegolnych elementow tablicy dzialalem nie na kopii, lecz na wlasciwym obiekcie. W tym momencie zaczalem wlasnie rozwazac uzycie slowa const, i stad moje pytanie.

0

Chodzi o to, że zwracam jakiś obiekt. Dajmy na to jakąś listę. I chcę mieć pewność, że tej listy mi nikt nie zmieni. Np. nie doda żadnego elementu, nie usunie, a nawet nie zmodyfikuje żadnego elementu listy. Np:

 
List<MyObj> list = obj.GetList();
//i teraz bym chciał, żeby np. nie było możliwe zrobienie:
list.Add(new MyObjs());

//ale też bym chciał, żeby nie było możliwe:
list[0].OneProperty = newValue;
4

@Juhas, jeśli chcesz, aby niemożliwa była modyfikacja kolekcji, to nie przekazujesz List<T>, która na to pozwala, lecz IEnumerable<T>. Jeśli nie chcesz modyfikować właściwości poszczególnych elementów, to uczyń je niemodyfikowalnymi, po prostu nie definiuj publicznych seterów.

0

No właśnie nie mogę nie robić publicznych setterów. Tzn. inaczej. Mam problem podobny do gościa, który pytał o ruchy królowej. Mam jedną klasę, która może modyfikować obiekty innej klasy. Ale inne klasy mogą jedynie odczytywać te obiekty. Ideałem byłoby c++ friend albo zwracanie obiektu przez stałą referencję. Innej możliwości nie widzę. No, pozostaje jeszcze Reflection, ale jednak wolałbym unikać takich fikołków.

0

Można też mieć różne zestawy obiektów - jeden mutowalny, używany przez te dwie klasy, które mogą mutować, drugi niemutowalny, dostępny dla reszty aplikacji.
Generalnie większość problemów idzie rozwiązać dobrą architekturą - może po prostu brakuje Ci jakiegoś wzorca, który pozwoliłby Ci tworzyć obiekty raz i nie trzeba byłoby ich modyfikować?

0

Nie, no właśnie potrzebuję je modyfikować, ale tylko w tej jednej klasie. A co z tymi zestawami obiektów? Znasz jakiś dobry wzorzec do tego? Bo póki co to moim rozwiązaniem jest zwracanie kopii takiej listy. Ale wiadomo, jakie to rozwiązanie, zwłaszcza jak lista jest duża.

1

List<T>.AsReadOnly => ReadOnlyCollection<T>

0

OK, a jak uniemożliwić zmianę poszczególnych elementów kolekcji? (to nie są typy proste)

0

A próbowałeś coś przypisać do elementu ReadOnlyCollection?

0

jak wspomniano wcześniej - zamień elementy kolekcji na strukturę, lub zrób z nich obiekty niemutowalne (private sety)
ewentualnie do metody przekazuj klony lub elementy owrapowane (dekorator?) w obiekt readonly

2
Juhas napisał(a):

Nie, no właśnie potrzebuję je modyfikować, ale tylko w tej jednej klasie. A co z tymi zestawami obiektów? Znasz jakiś dobry wzorzec do tego? Bo póki co to moim rozwiązaniem jest zwracanie kopii takiej listy. Ale wiadomo, jakie to rozwiązanie, zwłaszcza jak lista jest duża.

Jeśli zrobisz drugi zestaw obiektów, tak jak ja proponowałem, to i drugą listę będziesz musiał mieć.

Mi chodzi o coś takiego:

class Student
{
    public string Name { get; set; }
}

class ImmutableStudent
{
    public string Name { get; private set; }

    public ImmutableStudent(Student s)
    {
        this.Name = s.Name;
    }
}

I jak już masz gotową kolekcję obiektów Student, z już poustawianymi wartościami, to tworzysz listę obiektów ImmutableStudent, i jej używa reszta klas w aplikacji. Innego sposobu nie znam.

ŁF napisał(a):

List<T>.AsReadOnly => ReadOnlyCollection<T>

Tylko trzeba pamiętać, że ReadOnlyCollection wcale nie jest takie znowu read only:

var studentsList = new List<Student>()
{
    new Student { Name = "A" },
    new Student { Name = "B" },
    new Student { Name = "C" },
};

var readonlyStudents = studentsList.AsReadOnly();
studentsList.Add(new Student { Name = "readonly nie działa" });

foreach (var student in readonlyStudents)
{
    Console.WriteLine(student.Name);
}

Jak się chce mieć naprawdę niezmienną kolekcję, trzeba skorzystać z czegoś z przestrzeni System.Collections.Immutable - i trzeba to sobie ściągnąć z NuGeta, bo w standardowym frameworku tego nie ma.

Złoty Młot napisał(a):

jak wspomniano wcześniej - zamień elementy kolekcji na strukturę

Tylko bez przesady. Zamiana klasy na strukturę to generalnie jest zły pomysł. Strukury się stosuje w określonych przypadkach i taki typ musi spełniać określone warunki, żeby miał sens jako struktura.

1

Możesz spróbowac tak, jak wymyślisz jakieś sprytne dziedziczenie lub delegacje FriendClass(nie koniecznie słowem delegate ;) ) i fabryke by nie pisać tej śmiesznej podwójnek kropki tysiąc razy to to rozwiązanie może mieć ręce i nogi

    
 class NormalClass 
    {
        public string Name{ get; protected set; } // by można było dziedziczyć po normal class
        public string Surname { get; protected set; }
        public class FriendClass
        {
            public void SetFrienName(NormalClass friend, string name)
            {
                friend.Name = name;
            }
            public void SetFrienSurname(NormalClass friend, string surname)
            {
                friend.Surname = surname;
            }
        }
    }

albo

  
 class NormalClass 
    {
        private void DoSomething()
        public class FriendClass : NormalClass
        {
           public void Do()
           {
                 base.DoSomething();
           }
         }
    }  

Gdby friendClass i normal class miały długie implementacje mozesz zastosować słowo partial i zrobić każdą w osobnym pliku.
Jeśli to co zrobiłem wyżej zrobisz static, to bedziesz mógł napisać interface IFriend i do pisać do niego jako metode rozszerzeń SetFrienSurname, SetFrienName, a to pozwali Ci obdarzyć dowolną klase w programie implementującą IFriend dostępem do pól i metod prywatnych normalClass :D

ps pisalem wcześniej w komentarzu.

1 użytkowników online, w tym zalogowanych: 0, gości: 1