views:

58

answers:

2

Let's say I have a struct that contains local environments:

 public struct Environments
    {
        public const string Dev = "DEV";
        public const string Qa1 = "SQA";
        public const string Prod1 = "PROD";
        public const string Prod2 = "PROD_SA";
        public const string Uat = "UAT"; 
    }

And I'd like to pull a set of XElements out of an xml doc, but only those elements that have a key that matches a value in a struct.

this.environments =(from e in 
settings.Element("Settings").Element("Environments")
       .Elements("Environment")
       .Where( x => x.HasAttribute("name") )
        join f in [struct?] on e.Attribute("name") 
        equals [struct value?]).ToDictionary(...)

How would I go about doing this? Do I need reflection to get the values of the constants in the struct?

+1  A: 

First, I would probably add a static function to Environments to determine if a string "is an environment".

private static string[] allEnvirons;
public static bool IsEnvironment(string value)
{
    return allEnvirons.Contains(data, StringComparer.OrdinalIgnoreCase);
}

Then the only question is how to fill the allEnvirons variable. If the Envrionments class does not change much, you could just manually type up the list of constants (yes, it's repeating the constants, but only once and close by so you should remember to change both if changes need to be made). Alternatively, if Environments is changing often, you could use reflection to fill the array. Say:

allEnvirons = (from f in typeof(Environments)
                           .GetFields(Reflection.BindingFlags.Public |
                                      Reflection.BindingFlags.Static
               select (string)(f.GetValue(null))).ToArray()

Either way, your query becomes something like:

this.environments = (from e in settings.Element("Settings")
                                       .Element("Environments")
                                       .Elements("Environment")
                     where e.HasAttribute("name") &&
                           Environments.IsEnvironment(e.Attribute("name"))
                    ).ToDictionary(...);
Gideon Engelberth
Thanks, it was the GetValue(null) that was tripping me up. Makes sense after you look at it but it's counterintuitive.
jcollum
A: 

Any specific reason why you need to use a struct to define the different enviroments vs an Enum?

If you can use enum you could do something like this

public enum Enviroments
{   
    Dev,
    Qa1,
    Prod1,
    Prod2,
    Uat
}

    XDocument settings = XDocument.Load("Foo.xml");

    var matches = from e in settings.Descendants("Environment")
where Enum.IsDefined(typeof (Enviroments), e.Attribute("name"))
select e;
Foovanadil
If I use the struct the names of the environments and their key values are decoupled. I can then use those key values (e.g. "PROD_SA") in dictionaries but still have the syntactic sugar of defining the ProdSa environment as Environments.ProdSa. I'm trying to keep my comment brief, so I hope it makes sense.
jcollum
Yeah, comment makes sense but I still feel like an Enum is a reasonable choice. Remember you can decorate your Enum values with the Description attribute to add a Text value to the Enum and use that value as the key in a collection.Something simple like this: http://www.codeproject.com/KB/cs/enumwithdescription.aspx
Foovanadil
True; they both work and they both require reflection to get them to work the way I want.
jcollum
true. Reflection is required to get it the way you want it using my approach
Foovanadil
Actually I don't like the enum choice because the string values are locked behind a reflection call. I'd like to have values that I can easily use as store/retrieve for a Dictionary. To use an enum I'd have to reflect everytime I wanted to do that.
jcollum