Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a C# pattern for strongly typed class members with external set/get methods?

Tags:

I have the following structure and would like a solution with both benefits from the following two classes. The first class is using strings and strongly typed members:

public class UserSessionData
{
    private string Get(string key)
    {
        throw new NotImplementedException("TODO: Get from external source");
    }
    private void Set(string key, string value)
    {
        throw new NotImplementedException("TODO: Set in external source");
    }

    public string CustomerNumber {
        get { return Get("CustomerNumber"); }
        set { Set("CustomerNumber", value); }
    }
    public string FirstName {
        get { return Get("FirstName"); }
        set { Set("FirstName", value); }
    }
    public string LastName {
        get { return Get("LastName"); }
        set { Set("LastName", value); }
    }

    // ... a couple of hundreds of these
}

I can imagine an alternative being a Get and Set method with an enum parameter. Here is the second class:

public class UserSessionData
{
    public enum What {
        CustomerNumber, FirstName, LastName, // ...
    }

    public string Get (What what) { return MyExternalSource(what); }
    public string Set (What what, string value) { return MyExternalSource(what); }
}

But the consumer side of class #2 is not pretty:
UserSessionData.Get(UserSessionData.What.CustomerNumber)
Compare it to the first class: UserSessionData.CustomerNumber

Is there a strongly typed way of calling the Get and Set methods in my first class example? Stated another way: How do I get the benefits from both classes, i.e. the maintainability of strongly typed members and a nice-looking syntax?

like image 524
Simeon Avatar asked Jul 09 '13 14:07

Simeon


2 Answers

.Net 4.5 or newer

If you use .Net 4.5 or newer you can make use of CallerMemberNameAttribute so you can call it like this:

public string CustomerNumber {
    get { return Get(); }
}

To make this work, modify the Get method by adding the attribute to the parameter:

private string Get([CallerMemberName] string key)
{
    ...
}

Performance notice: The compiler will insert a string as parameter at the calling site, so this is fast.


.Net 4.0 or earlier

If you use .Net 4.0 or earlier, you can still use strongly typed property names instead of typing strings manually, but you need to implement a method like this to extract the property name from an Expression, and then you can call it using an expression:

public string CustomerNumber {
    get { return Get(() => this.CustomerNumber ); }
}

The setters can be implemented in the same fashion.

Performance notice: The string is extracted at runtime, so this is slower than using CallerMemberNameAttribute.

like image 110
lightbricko Avatar answered Sep 24 '22 06:09

lightbricko


You can use a T4 template to generate the class. In the T4 template you just name all the properties - you could get them through reflection from an enum, too, but using a string array is simpler.

Add New Item -> Text template

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ output extension=".cs" #>
<# var properties = new string [] {
      "CustomerNumber", // This is where you define the properties
      "FirstName",
      "LastName"
}; #>
class UserSessionData {
<#  
  foreach (string propertyName in properties) 
  { #>
  public string <#= propertyName #>{
    get { return Get("<#= propertyName #>"); }
    set { Set("<#= propertyName #>", value); }
  }
<# } #>
}

More info @ Design-Time Code Generation by using T4 Text Templates

like image 23
Alex Avatar answered Sep 23 '22 06:09

Alex