2013-01-18 20 views
5

Ich arbeite auf einer Online-Buchungsseite (Fluggesellschaft) und ich möchte überprüfen, ob die gewählte Route des Benutzers/Kunden nach einigen Einstellungen gültig ist. Die bestehenden Codes verwenden eine Menge Enums und ich habe viele If/If Else/Else gemacht, um eine bestimmte Enum einer bestimmten Aktion zuzuordnen, die ich wollte. What I want to do is to write a enum-specific method that would do the mapping for me. Is there any standard way to do this?Karte enum zu einer Funktion/Aktion mit Enum-spezifischen Methode

Hier ist eine vereinfachte Version des Codes App die gleichen Klassennamen/ENUM-Werte usw. aus der realen App:

// real app has 9 members, shortened for simplicity's sake 
public enum RegionType 
{ 
    Station, 
    Country, 
    All 
} 

public enum Directionality 
{ 
    Between, 
    From, 
    To 
} 

// simplified version 
public class Flight 
{ 
    public RegionType RegionType { get; set; } 
    public RegionType TravelRegionType { get; set; } 
    public string RegionCode { get; set; } 
    public string TravelRegionCode { get; set; } 
    public string RegionCountryCode { get; set; } 
    public string TravelRegionCountryCode { get; set; } 
    public Directionality Directionality { get; set; } 
} 

Hier einige Beispiel-Nutzung:

// valid flight 
    Flight flight = new Flight() 
    { 
     RegionCode = "NY", 
     CountryCode = "JP", 
     RegionType = RegionType.Station, 
     TravelRegionType = RegionType.Country, 
     Directionality = Directionality.Between 
    }; 

    // these are the station code/country code that user selected 
    // needs to be validated against the Flight object above 
    var userSelectedRoutes = new List<KeyValuePair<string, string>>() 
    { 
     new KeyValuePair<string, string>("NY", "JP"), 
     new KeyValuePair<string, string>("NY", "AU"), 
     new KeyValuePair<string, string>("JP", "NY") 
    }; 

Einige Code-Validierung I schrieb, um verschachteltes if/else if/else zu löschen enum passender:

Und hier ist der unordentliche Code, den ich ändern will:

if (flight.RegionType == RegionType.Station 
    && flight.TravelRegionType == RegionType.Country) 
{ 
    return userSelectedRoutes.Any(route => 
      IsRouteValid(flight.Directionality, route.Key, route.Value, 
      flight.RegionCode, flight.TravelRegionCode)); 
} 
else if (flight.RegionType == RegionType.Country 
&& flight.TravelRegionType == RegionType.Station) 
{ 
    return userSelectedRoutes.Any(route => 
      IsRouteValid(flight.Directionality, route.Key, route.Value, 
      flight.CountryCode, flight.RegionCode)); 
} 
else if (flight.RegionType == RegionType.Station 
&& flight.TravelRegionType == RegionType.Station) 
{ 
    return userSelectedRoutes.Any(route => 
      IsRouteValid(flight.Directionality, route.Key, route.Value, 
         flight.RegionCode, flight.TravelRegionCode)); 
} 
else if (flight.RegionType == RegionType.Station 
&& flight.TravelRegionType == RegionType.All) 
{ 
    return userSelectedRoutes.Any(route => 
      IsRouteValid(flight.Directionality, route.Key, route.Value, 
         flight.RegionCode, route.Value)); 
} 
else if (flight.RegionType == RegionType.All 
&& flight.TravelRegionType == RegionType.Station) 
{ 
    return userSelectedRoutes.Any(route => 
      IsRouteValid(flight.Directionality, route.Key, route.Value, 
      route.Key, flight.TravelRegionCode)); 
} 
else if (flight.RegionType == RegionType.All 
     && flight.TravelRegionType == RegionType.All) 
{ 
    return true; 
} 
else 
{ 
    return false; 
} 

Legende:

RegionCode = Abfahrtsbahnhof/Herkunft
TravelRegionCode = Ankunftsbahnhof/Ziel
Between = Routen müssen nur aus dem seine gegebenen Abfahrts- und Ankunftsbahnhof und umgekehrt (ex NY-JP oder JP-NY)
From = von einer bestimmten Station zu beliebigen Strecken (ex AU-All)
To = alle Routen zu einer bestimmten Station (ex All -AU)

Wenn Sie feststellen können, die .Any aller oben genannten Bedingungen sind die gleichen mit geringfügigen Änderungen. Ich möchte, wenn möglich, die Code-Redundanz reduzieren. Ich habe KeyValuePair verwendet, also habe ich sowohl Abfahrtsbahnhof als auch Ankunftsbahnhof auf einem einzigen Datentyp.

Irgendwelche Ideen, wie ich diesen Code weniger chaotisch/schön machen könnte? Ich weiß, dass ich auch IsRouteValid() hart codiert habe, aber ich bin 100% sicher, dass Directionality nur die 3 möglichen Kombinationen haben konnte. RegionType auf der anderen Seite könnte mehrere verschiedene Kombinationen wie Station-Station, Bahnhof-Country, Country-Station, Land-Land usw. haben

Erwartete Ausgabe:

Gültig/Wahre für die erste Strecke (NY- JP)
Ungültige/Falsch für die zweite Route (NY-AU)
Gültig/Wahre für den dritten Weg (JP-NY) [seit Directionality ist Between]

Vielen dank für das Lesen dieses sehr lange Abfrage und dank im Voraus für dein Feedba ck und Vorschläge.

Ähnliche Beitrag:

Enum and Dictionary

Antwort

17

Ein Weg, solche Enum-Aktion-Mappings zu handhaben ist, mit Wörterbücher.Hier ein Beispiel:

public enum MyEnum 
{ 
    EnumValue1, 
    EnumValue2, 
    EnumValue3 
} 

private IDictionary<MyEnum, Action> Mapping = new Dictionary<MyEnum, Action> 
    { 
     { MyEnum.EnumValue1,() => { /* Action 1 */ } }, 
     { MyEnum.EnumValue2,() => { /* Action 2 */ } }, 
     { MyEnum.EnumValue3,() => { /* Action 3 */ } } 
    }; 

public void HandleEnumValue(MyEnum enumValue) 
{ 
    if (Mapping.ContainsKey(enumValue)) 
    { 
     Mapping[enumValue](); 
    } 
} 

Natürlich können Sie auch Func statt Action verwenden können, um Parameter zu verarbeiten.

Edit:

Wie Sie nicht nur eine Aufzählung verwenden, sondern Paare von Aufzählungen würden Sie das Beispiel oben einstellen müssen, um zu vielleicht eine Tuple oder eine andere Art und Weise behandelt die ENUM-Werte zu aggregieren.

4

@MatthiasG Vorschlag folgend, hier ist der Code, den ich schriftlich beendet hatte bis:

private List<KeyValuePair<RegionType, string>> 
       GetRegionTypeAndValueMapping(Flight flight, 
              RegionType regionType, 
              RegionType travelRegionType) 
{ 
    var mapping = new List<KeyValuePair<RegionType, string>>(); 
    if(regionType == RegionType.Station) 
    { 
     mapping.Add(new KeyValuePair<RegionType, string> 
          (RegionType.Station, flight.RegionCode)); 
    } 
    else if(regionType == RegionType.Country) 
    { 
     mapping.Add(new KeyValuePair<RegionType, string> 
          (RegionType.Country, flight.RegionCountryCode)); 
    } 
    else if(regionType == RegionType.All) 
    { 
     mapping.Add(new KeyValuePair<RegionType, string> 
          (RegionType.All, null)); 
    } 

    if(travelRegionType == RegionType.Station) 
    { 
     mapping.Add(new KeyValuePair<RegionType, string> 
          (RegionType.Station, flight.TravelRegionCode)); 
    } 
    else if(travelRegionType == RegionType.Country) 
    { 
     mapping.Add(new KeyValuePair<RegionType, string> 
          (RegionType.Country, 
          flight.TravelRegionCountryCode)); 
    } 
    else if(travelRegionType == RegionType.All) 
    { 
     mapping.Add(new KeyValuePair<RegionType, string> 
          (RegionType.All, null)); 
    } 

    return mapping; 
} 

I List<KeyValuePair<RegionType, string>> verwendet, weil Dictionary keine Schlüssel Duplikate nicht zulässt. Meine Schlüssel sind von RegionType enum und es wird eine Zeit geben, in der sowohl die Abfahrts- als auch die Ankunftsstation dieselbe RegionType enum haben. (d. h. Station-Station, Land-Land und All-All).

// Copyright (c) 2010 Alex Regueiro 
// Licensed under MIT license, available at 
// <http://www.opensource.org/licenses/mit-license.php>. 
// Published originally at 
// <http://blog.noldorin.com/2010/05/combinatorics-in-csharp/>. 
// Version 1.0, released 22nd May 2010. 

// modified by moi to be a generator 
public static IEnumerable<T[]> GetPermutations<T>(IList<T> list, 
                int? resultSize, 
                bool withRepetition) 
{ 
    if (list == null) 
    { 
     throw new ArgumentNullException("Source list is null."); 
    } 

    if (resultSize.HasValue && resultSize.Value <= 0) 
    { 
     throw new ArgumentException("Result size must be any 
            number greater than zero."); 
    } 

    var result = new T[resultSize.HasValue ? resultSize.Value : list.Count]; 
    var indices = new int[result.Length]; 
    for (int i = 0; i < indices.Length; i++) 
    { 
     indices[i] = withRepetition ? -1 : i - 1; 
    } 

    int curIndex = 0; 
    while (curIndex != -1) 
    { 
     indices[curIndex]++; 
     if (indices[curIndex] == list.Count) 
     { 
      indices[curIndex] = withRepetition ? -1 : curIndex - 1; 
      curIndex--; 
     } 
     else 
     { 
      result[curIndex] = list[indices[curIndex]]; 
      if (curIndex < indices.Length - 1) 
      { 
       curIndex++; 
      } 
      else 
      { 
       yield return result; 
      } 

     } 
    } 
} 

Okay, betrogen ich. : P Ich brauchte eine Methode, die Permutationen mit Wiederholungen berechnet, also anstatt zu schreiben, googelte ich. (hehe) Der Grund, warum ich Permutationen verwendet habe, ist die Vermeidung einer harten Codierung aller möglichen Kombinationen, die RegionType haben könnte. Ich modifizierte Alex Regueiros Methode, um ein Generator zu sein, so dass ich Linq dafür verwenden konnte. Weitere Informationen zu Permutation und Kombination finden Sie unter this very excellent math stackexchange post.

Ich modifizierte IsRouteValid(), um RegionType.All zu handhaben, dessen Wert null ist.

Hier ist die modifizierte Version:

private bool IsRouteValid(Directionality direction, string origin, 
          string destination, string departure, 
          string arrival) 
{ 
    // ** == All stations/countries 
    if ((origin == null && departure == "**") && 
     (destination == null && arrival == "**")) 
    { 
     return true; 
    } 
    else if (origin == null && departure == "**") 
    { 
     return destination.Equals(arrival, StringComparison.OrdinalIgnoreCase); 
    } 
    else if (destination == null && arrival == "**") 
    { 
     return origin.Equals(departure, StringComparison.OrdinalIgnoreCase); 
    } 

    // both departure station and arrival station 
    if (direction == Directionality.Between) 
    { 
      return (origin.Equals(departure, 
        StringComparison.OrdinalIgnoreCase) && 
        destination.Equals(arrival, 
        StringComparison.OrdinalIgnoreCase) || 
        origin.Equals(arrival, 
        StringComparison.OrdinalIgnoreCase) &&   
        destination.Equals(departure, 
        StringComparison.OrdinalIgnoreCase)); 
    } 
    else if (direction == Directionality.From) 
    { 
     return (origin.Equals(arrival, StringComparison.OrdinalIgnoreCase)); 
    } 
    else if (direction == Directionality.To) 
    { 
     return (destination.Equals(departure, 
       StringComparison.OrdinalIgnoreCase)); 
    } 

    return false; 
} 

Es zeigen Zeit!

Ich habe diesen Code erstellt, um zu demonstrieren, wie ich das Ergebnis erhalten habe, das mit den oben erwarteten Ergebnissen übereinstimmt.

foreach(var route in userSelectedRoutes) 
    { 
     foreach(var validFlight in validFlights) 
     { 
      bool condition = IsRouteValid(flight.Directionality, 
              route.Key, 
              route.Value, 
              validFlight.First().Value, 
              validFlight.Last().Value); 

      Console.WriteLine(string.Format("{0}-{1} {2}", 
               route.Key,  
               route.Value, 
               condition.ToString())); 
     } 
    } 

Ergebnisse:

expected results screenshot

Hinweis:

.Dump() ist eine Linqpad Erweiterung.

Verwandte Themen