definiowanie listy stringów

0

Chciałbym zadeklarować listę pewnych stringów np: "Kot", "Pies", "Mysz", jako zdefiniowany zbiór, z którego potem bedę sobie wybierać. Chcę to zrobić, żeby uniknąć pomyłek np przy przekazywaniu wartości do metody, gdy wiem, że np wartości tam przekazywane mogę być tylko z tej listy oraz przy sprawdzaniu czasem wartości jakiegoś stringa z danym z tej listy wcześniej zadeklarowanej.
Wtedy zaglądałebym tylko do tej listy, którą już stworzyłem wcześniej.

Macie jakieś pomysły jak to elegancko zrobić, tak żeby dodatkowo środowisko VS podpowiadało zawartość tej listy stringów, jak robi to w przypadku zdefiniowanych już klas lub metod?

0

enum to jedno, a lista stringow to drugie.. co jesli bedzie chcial stringa "mama w kaloszach" ?

niestety 'podpowiadanie' uzyskasz tylko i wylacznie definiujac elementy konkretnych typow danych. lista stringow zas to sa dane, tak wiec mowiac krotko - nie da sie.

ale mozna uzyskac cos podobnego niewprost. zdefiniuj enuma wg podpowiedzi rev'a, zawierajacego wpisy 'kot', 'pies', 'mysz', 'mamawkaloszach' - bez spacji beda poprawne - a potem .... w miejscu w ktorym chces zdostac konkretny napis, musisz wartosc enuma przetlumaczyc na string, np:

public enum Rodzaje {kot, pies, mysz, kotwbutach}
public static string RodzajNaString(/*this*/ Rodzaj value)
{   switch(value)
    {   case Rodzaj.kot: return "kot";
 .....
        case Rodzaj.kotwbutach: return "kot ! w ! butach";
    }
}

jelsi uzywasz .net3.5 w gore, odkomentuj this - wtedy uzyskasz wygodniejsza extensionmethod
no i oczywiste uzycie

void blah(Rodzaj rodz)
{
    MessageBox.Show( "Odwiedzil mnie dzis: " + RodzajNaString(rodz) );
    // MessageBox.Show( "Odwiedzil mnie dzis: " + rodz.RodzajNaString() );
}
0

Dzięki wielkie. :D
O to mi właśnie chodziło.

0

Zamiast RodzajNaString wystarczy tablica stringów i odwolywanie po indeksie zamieniajac enuma na int - bedzie krócej.

0

Można to zrobić bez niebezpiecznych CASE. Za pomocą refleksji i klasy FieldInfo. A wygląda to tak:

public partial class Form1 : Form
    {
        enum Enumeracja
        {
            [Description("Mój zwierzak to pies")]
            Pies,
            [Description("Mój zwierzak to kot")]
            Kot,
            [Description("Moja mama ma psa")]
            MamaWKaloszach
        }

        public static string PobierzOpisEnumeratora(object WartoscEnumeratora)
        {
                string zwracanaWartosc = "";
                try
                {
                FieldInfo fieldInfo = WartoscEnumeratora.GetType().GetField(WartoscEnumeratora.ToString());
                DescriptionAttribute[] Atrybuty = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
                    //Jeżeli nie określono opisu (description) to zwróć "nazwę" enumeratora
                zwracanaWartosc = ((Atrybuty.Length > 0) ? Atrybuty[0].Description : WartoscEnumeratora.ToString());
                }
                catch( NullReferenceException ex)
                {
                    zwracanaWartosc = "brak";
                }
                return zwracanaWartosc;
        }

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            MessageBox.Show(PobierzOpisEnumeratora(Enumeracja.MamaWKaloszach));
        }
    }

Metoda PobierzOpisEnumeratora pobiera wartośc atrybutu Description pola enumeratora. Jeżeli Description nie jest podane, to zwraca nazwę pola enumeratora. Description to zwykły atrybut, który można stosować na większości obiektów C#. jest to zwyczajny string.

uwaga. Trzeba dodać linię na początku:
using System.Reflection;

0

tak, z tym ze zwroc uwage ze raz ze bedzie N razy wolniejsze przez sam fakt uzycia reflekcji, a dwa - umieszczajac sobie wartosc stringa w atrybucie 'description' automatycznie odcinasz sobie droge do np. konstruowania go w locie (odmiana, przypadki, itpwtf) czy dynamicznej lokalizacji w oparciu o CurrentCultureInfo, itp itd

poza tym... nie widze nic niebezpieczniejszego we switch/case nad wpisywanie stringa w description. dokladnie taka sama mozliwosc popelnienia bledu!

i... zeby przypieczetowac.. atrybuty nie zostaly zaprojektowane by trzymac DANE. one zostana żywcem wyryte w pozniejszym skompilowanym assembly. atrybuty sa po to, by umieszczac w nich metadane na temat konstrukcji obiektow/pol/etc, w tym np. opisujace stale zachowania, powiazania, informacje dla automatow przetwarzajacych kod czy assembly'ie itp. stad, Twoj przyklad ma wiec u swoich podstaw powazny blad merytoryczny, ktory moglbys ominac wprowadzajac jeden skok wiecej - stworzyc atrybut ktory bedzie trzymal KLUCZ do tablicy-czy-tez-Resources - a metoda tlumaczaca na string - niech uzywa klucza i wyciaga z tablicy-czy-tez-Resources konkretna, zlokalizowana/przetworzona/etc wartosc.. oczywiscie, malo komu sie chce, ale tak to powinno wygladac

*) Atrybut description nie o pokazywania uzykownikowi koncowemu, tylko dla dewelopera, zeby w designerze w Properties sie opis przeznaczenia tego czegos wyswietlil!
http://msdn.microsoft.com/en-us/library/system.componentmodel.descriptionattribute.aspx

0

tak, z tym ze zwroc uwage ze raz ze bedzie N razy wolniejsze przez sam fakt uzycia reflekcji, a dwa - umieszczajac sobie wartosc stringa w atrybucie 'description' automatycznie odcinasz sobie droge do np. konstruowania go w locie (odmiana, przypadki, itpwtf) czy dynamicznej lokalizacji w oparciu o CurrentCultureInfo, itp itd

No tak, ale jak napisał autor: "jak to elegancko zrobić, tak żeby dodatkowo środowisko VS podpowiadało zawartość tej listy stringów, jak robi to w przypadku zdefiniowanych już klas lub metod?". To to jest rozwiązanie tego problemu. Lokalizacja w oparciu o CurrentCultureInfo też wydaje mi się możliwa, chociaż rzeczywiście ciut trudniejsza.

poza tym... nie widze nic niebezpieczniejszego we switch/case nad wpisywanie stringa w description. dokladnie taka sama mozliwosc popelnienia bledu!

No ja unikam jednak jakoś wielokrotnego caseowania.

i... zeby przypieczetowac.. atrybuty nie zostaly zaprojektowane by trzymac DANE. one zostana żywcem wyryte w pozniejszym skompilowanym assembly. atrybuty sa po to, by umieszczac w nich metadane na temat konstrukcji obiektow/pol/etc, w tym np. opisujace stale zachowania, powiazania, informacje dla automatow przetwarzajacych kod czy assembly'ie itp. stad,

A czy to źle? Ja rozumiem, że to by był kawałek większego systemu i byłyby potrzeby wskazujące na wady tego rozwiązania, ale do prościutkich rzeczy nie trzeba tego rozszerzać.

Twoj przyklad ma wiec u swoich podstaw powazny blad merytoryczny, ktory moglbys ominac wprowadzajac jeden skok wiecej - stworzyc atrybut ktory bedzie trzymal KLUCZ do tablicy-czy-tez-Resources - a metoda tlumaczaca na string - niech uzywa klucza i wyciaga z tablicy-czy-tez-Resources konkretna, zlokalizowana/przetworzona/etc wartosc.. oczywiscie, malo komu sie chce, ale tak to powinno wygladac

No możliwe. Tak samo możnaby wczytywać tekst ze zdalnej bazy danych gdzie by było tłumaczenie itd. No ale po co? Autor nie pisał raczej o takiej potrzebie. Ale oczywiście w aplikacjach wielojęzycznych takie rozwiązanie będzie idealne jak piszesz. Myślę że pisanie o lokalizacji aplikacji w kontekście pytania autora jest lekką przesadą.

*) Atrybut description nie o pokazywania uzykownikowi koncowemu, tylko dla dewelopera, zeby w designerze w Properties sie opis przeznaczenia tego czegos wyswietlil!
http://msdn.microsoft.com/en-u[...]odel.descriptionattribute.aspx

Atrybut description na polach enumeratora raczej nigdzie się nie przydaje, więc można go spokojnie użyć do tego celu. A jak nie to można też napisać własny Atrybut, ale po co? Czyż nie jest to celowaniem armatą do muchY? :)

pozdr

0

Krótkie w zapisie, wygodne w użyciu, łatwo rozszerzalne (OOP):

public class Zwierzak
{
    private static Dictionary<string, Zwierzak> zwiarzaki = new Dictionary<string, Zwierzak>();
    public static IDictionary<string, Zwierzak> Wszystkie
    {
        get { return zwiarzaki; }
    }

    private string wartosc;
    private Zwierzak(string wartosc) 
    {
        zwiarzaki.Add(wartosc, this);
        this.wartosc = wartosc; 
    }

    public static implicit operator string(Zwierzak zwierzak)
    {
        return zwierzak.wartosc;
    }

    public override string ToString()
    {
        return wartosc;
    }

    public static Zwierzak Kot = new Zwierzak("kotecek");
    public static Zwierzak Pies = new Zwierzak("piesecek");
    public static Zwierzak Mysz = new Zwierzak("myszka");
}
//...
Zwierzak zwirz = Zwierzak.Kot;
MessageBox.Show("mój zwierzak to " + zwirz);
MessageBox.Show(String.Format("{0} jest super !", zwirz));
zwirz = Zwierzak.Wszystkie["Kot"];
if(Zwierzak.Wszystkie.TryGetValue("Pies", out zwirz))
{
   MessageBox.Show(String.Format("Znalazłem \"{0}\"", zwirz));
}

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