Jaki jest najbardziej efektywny sposób tworzenia stałego (nigdy nie zmieniającego się w czasie wykonywania) odwzorowania string
s na int
s?
Próbowałem użyć const Dictionary , ale to nie wyszło.
Mógłbym zaimplementować niezmienny wrapper z odpowiednią semantyką, ale nadal nie wydaje się to całkowicie poprawne.
Dla tych, którzy o to pytali, implementuję IDataErrorInfo w wygenerowanej klasie i szukam sposobu, aby wyszukać columnName w mojej tablicy deskryptorów.
Nie byłem świadomy (literówka podczas testowania! D'oh!), Że przełącznik akceptuje ciągi, więc tego będę używał. Dzięki!
c#
.net
collections
dictionary
constants
David Schmitt
źródło
źródło
Odpowiedzi:
Tworzenie prawdziwie generowanego w czasie kompilacji słownika stałego w języku C # nie jest tak naprawdę prostym zadaniem. Właściwie żadna z przedstawionych tutaj odpowiedzi naprawdę tego nie osiąga.
Jest jednak jedno rozwiązanie, które spełnia Twoje wymagania, choć niekoniecznie jest przyjemne; pamiętaj, że zgodnie ze specyfikacją C # tablice przypadków przełączników są kompilowane do postaci stałych tablic skoku z mieszaniem. Oznacza to, że są to stałe słowniki, a nie seria instrukcji jeśli-inaczej. Rozważ więc taką instrukcję przełączania:
switch (myString) { case "cat": return 0; case "dog": return 1; case "elephant": return 3; }
To jest dokładnie to, czego chcesz. I tak, wiem, jest brzydki.
źródło
W obecnej strukturze istnieje bardzo niewiele niezmiennych kolekcji. Przychodzi mi do głowy jedna stosunkowo bezbolesna opcja w .NET 3.5:
Use
Enumerable.ToLookup()
-Lookup<,>
klasa jest niezmienna (ale wielowartościowa po prawej stronie); możesz to zrobić wDictionary<,>
dość łatwy sposób:Dictionary<string, int> ids = new Dictionary<string, int> { {"abc",1}, {"def",2}, {"ghi",3} }; ILookup<string, int> lookup = ids.ToLookup(x => x.Key, x => x.Value); int i = lookup["def"].Single();
źródło
enum Constants { Abc = 1, Def = 2, Ghi = 3 } ... int i = (int)Enum.Parse(typeof(Constants), "Def");
źródło
Oto najbliższa rzecz, jaką można znaleźć w „Słowniku CONST”:
public static int GetValueByName(string name) { switch (name) { case "bob": return 1; case "billy": return 2; default: return -1; } }
Kompilator będzie wystarczająco inteligentny, aby zbudować kod tak czysty, jak to tylko możliwe.
źródło
Jeśli korzystam z 4.5+ Framework, użyłbym ReadOnlyDictionary (także ReadOnly Collection dla list), aby wykonać mapowania / stałe tylko do odczytu. Jest zaimplementowany w następujący sposób.
static class SomeClass { static readonly ReadOnlyDictionary<string,int> SOME_MAPPING = new ReadOnlyDictionary<string,int>( new Dictionary<string,int>() { { "One", 1 }, { "Two", 2 } } ) }
źródło
private static readonly Dictionary<string, string> _yourDictionaryName = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase) { { "One",1 }, { "Two",2 }, { "Three",3 }, };
Tak to zrobiłem.readonly Dictionary<TKey, TValue>
nie jest odpowiednikiem aReadOnlyDictionary<TKey, TValue>
. W rzeczywistości sposób, w jaki są one „tylko do odczytu”, jest w zasadzie przeciwieństwem. Zobacz: dotnetfiddle.net/v0l4aA .Dlaczego nie używać przestrzeni nazw lub klas do zagnieżdżania wartości? Może być niedoskonały, ale jest bardzo czysty.
public static class ParentClass { // here is the "dictionary" class public static class FooDictionary { public const string Key1 = "somevalue"; public const string Foobar = "fubar"; } }
Teraz możesz uzyskać dostęp do .ParentClass.FooDictionary.Key1 itp.
źródło
Nie jestem pewien, dlaczego nikt o tym nie wspomniał, ale w C # dla rzeczy, których nie mogę przypisać const, używam statycznych właściwości tylko do odczytu.
Przykład:
public static readonly Dictionary<string, string[]> NewDictionary = new Dictionary<string, string[]>() { { "Reference1", Array1 }, { "Reference2", Array2 }, { "Reference3", Array3 }, { "Reference4", Array4 }, { "Reference5", Array5 } };
źródło
Wydaje się, że nie ma standardowego niezmiennego interfejsu dla słowników, więc niestety utworzenie opakowania wydaje się być jedyną rozsądną opcją.
Edycja : Marc Gravell znalazł ILookup, którego przegapiłem - pozwoli ci to przynajmniej uniknąć tworzenia nowego opakowania, chociaż nadal musisz przekształcić słownik za pomocą .ToLookup ().
Jeśli jest to potrzeba ograniczona do określonego scenariusza, lepiej byłoby, gdybyś miał interfejs bardziej zorientowany na logikę biznesową:
interface IActiveUserCountProvider { int GetMaxForServer(string serverName); }
źródło
Po prostu kolejny pomysł, ponieważ wiążę się z combobox winforms:
public enum DateRange { [Display(Name = "None")] None = 0, [Display(Name = "Today")] Today = 1, [Display(Name = "Tomorrow")] Tomorrow = 2, [Display(Name = "Yesterday")] Yesterday = 3, [Display(Name = "Last 7 Days")] LastSeven = 4, [Display(Name = "Custom")] Custom = 99 }; int something = (int)DateRange.None;
Aby uzyskać wartość int z nazwy wyświetlanej z :
public static class EnumHelper<T> { public static T GetValueFromName(string name) { var type = typeof(T); if (!type.IsEnum) throw new InvalidOperationException(); foreach (var field in type.GetFields()) { var attribute = Attribute.GetCustomAttribute(field, typeof(DisplayAttribute)) as DisplayAttribute; if (attribute != null) { if (attribute.Name == name) { return (T)field.GetValue(null); } } else { if (field.Name == name) return (T)field.GetValue(null); } } throw new ArgumentOutOfRangeException("name"); } }
stosowanie:
var z = (int)EnumHelper<DateRange>.GetValueFromName("Last 7 Days");
źródło
Dlaczego nie:
public class MyClass { private Dictionary<string, int> _myCollection = new Dictionary<string, int>() { { "A", 1 }, { "B", 2 }, { "C", 3 } }; public IEnumerable<KeyValuePair<string,int>> MyCollection { get { return _myCollection.AsEnumerable<KeyValuePair<string, int>>(); } } }
źródło