Keep enum-to-object mapping with enum class? - c#

I frequently need a global hard-coded mapping between an enum and another object (a string in this example). I want to co-locate the enum and mapping definitions to clarify maintenance.
As you can see, in this example, an annoying class with one static field is created.
public enum EmailTemplates
{
// Remember to edit the corresponding mapping singleton!
WelcomeEmail,
ConfirmEmail
}
public class KnownTemplates
{
public static Dictionary<EmailTemplates, string> KnownTemplates;
static KnownTemplates() {
KnownTemplates.Add(EmailTemplates.WelcomeEmail, "File1.htm");
KnownTemplates.Add(EmailTemplates.ConfirmEmail, "File2.htm");
}
}
Sometimes the mapping class can have more function and a meaningful name, and the mapping activity can even be private. But that only pollutes the maintenance/correlation problem.
Anyone have a good pattern for this?

You can use attributes to annotate the enumeration and then use reflection to build the dictionary.
[AttributeUsage(AttributeTargets.Field)]
sealed class TemplateAttribute : Attribute {
public TemplateAttribute(String fileName) {
FileName = fileName;
}
public String FileName { get; set; }
}
enum EmailTemplate {
[Template("File1.htm")]
WelcomeEmail,
[Template("File2.htm")]
ConfirmEmail
}
class KnownTemplates {
static Dictionary<EmailTemplate, String> knownTemplates;
static KnownTemplates() {
knownTemplates = typeof(EmailTemplates)
.GetFields(BindingFlags.Static | BindingFlags.Public)
.Where(fieldInfo => Attribute.IsDefined(fieldInfo, typeof(TemplateAttribute)))
.Select(
fieldInfo => new {
Value = (EmailTemplate) fieldInfo.GetValue(null),
Template = (TemplateAttribute) Attribute
.GetCustomAttribute(fieldInfo, typeof(TemplateAttribute))
}
)
.ToDictionary(x => x.Value, x => x.Template.FileName);
}
}
If you do this a lot you can create a more general generic function that combines enumeration values with an attribute associated with that enumeration value:
static IEnumerable<Tuple<TEnum, TAttribute>> GetEnumAttributes<TEnum, TAttribute>()
where TEnum : struct
where TAttribute : Attribute {
return typeof(TEnum)
.GetFields(BindingFlags.Static | BindingFlags.Public)
.Where(fieldInfo => Attribute.IsDefined(fieldInfo, typeof(TAttribute)))
.Select(
fieldInfo => Tuple.Create(
(TEnum) fieldInfo.GetValue(null),
(TAttribute) Attribute.GetCustomAttribute(fieldInfo, typeof(TAttribute))
)
);
}
And use it like this:
knownTemplates = GetEnumAttributes<EmailTemplate, TemplateAttribute>()
.ToDictionary(tuple => tuple.Item1, tuple => tuple.Item2.FileName);
For even more fun you can create an extension method:
static class EmailTemplateExtensions {
static Dictionary<EmailTemplate, String> templates;
static EmailTemplateExtensions() {
templates = GetEnumAttributes<EmailTemplate, TemplateAttribute>()
.ToDictionary(tuple => tuple.Item1, tuple => tuple.Item2.FileName);
}
public static String FileName(this EmailTemplate emailTemplate) {
String fileName;
if (templates.TryGetValue(emailTemplate, out fileName))
return fileName;
throw new ArgumentException(
String.Format("No template defined for EmailTemplate.{0}.", emailTemplate)
);
}
}
Then calling EmailTemplate.ConfirmEmail.FileName() will return File2.htm.

Here is an approach which worked pretty well for me.
public class BaseErrWarn : Attribute
{
public string Code { get; set; }
public string Description { get; set; }
public BaseErrWarn(string code, string description)
{
this.Code = code;
this.Description = description;
}
}
public enum ErrorCode
{
[BaseErrWarn("ClientErrMissingOrEmptyField", "Field was missing or empty.")] ClientErrMissingOrEmptyField,
[BaseErrWarn("ClientErrInvalidFieldValue", "Not a valid field value.")] ClientErrInvalidFieldValue,
[BaseErrWarn("ClientErrMissingValue", "No value passed in.")] ClientErrMissingValue
}
Now you can use reflection to map the Enum to the BaseErrWarn class:
public static BaseErrWarn GetAttribute(Enum enumVal)
{
return (BaseErrWarn)Attribute.GetCustomAttribute(ForValue(enumVal), typeof(BaseErrWarn));
}
private static MemberInfo ForValue(Enum errorEnum)
{
return typeof(BaseErrWarn).GetField(Enum.GetName(typeof(BaseErrWarn), errorEnum));
}
Here is an example which uses this mapping to map an Enum to an object and then pull fields off of it:
public BaseError(Enum errorCode)
{
BaseErrWarn baseError = GetAttribute(errorCode);
this.Code = baseError.Code;
this.Description = baseError.Description;
}
public BaseError(Enum errorCode, string fieldName)
{
BaseErrWarn baseError = GetAttribute(errorCode);
this.Code = baseError.Code;
this.Description = baseError.Description;
this.FieldName = fieldName;
}

Normally, when you want to add extra info or behaviors to your enum elements, that means you need a full blown class instead. You can borrow from (old-)Java the type-safe enum pattern and create something like this:
sealed class EmailTemplate {
public static readonly EmailTemplate Welcome = new EmailTemplate("File1.html");
public static readonly EmailTemplate Confirm = new EmailTemplate("File2.html");
private EmailTemplate(string location) {
Location = location;
}
public string Location { get; private set; }
public string Render(Model data) { ... }
}
Now you can associate any properties or methods to your elements, like Location and Render above.

Related

How can I know if some method has called that has a specific attribute in c#

class SampleClass
{
[SampleAttribute]
public void SampleMethod()
{
}
}
If there is a method like the above code. How can I know the method has called that has a specific attribute(In this case the attribute is 'SampleAttribute')? I know how to find methods that have specific attributes. But I don't know how to figure out when the method has called that has a specific attribute
You can do it in a few ways. But first, let's add some value to the SampleAttribute, to be sure, that everything is working:
[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
public class SampleAttribute : Attribute
{
public SampleAttribute(string text)
{
Text = text;
}
public string Text { get; private set; }
}
And specify the attribute value to the method:
public class SampleClass
{
[SampleAttribute("This is attribute text")]
public void SampleMethod() { }
}
Now, using the reflection mechanism, we can extract the attribute value from the object:
var sampleClass = new SampleClass();
ExtractSampleAttributeValue(sampleClass);
private static string ExtractSampleAttributeValue(SampleClass sampleClass)
{
var methods = sampleClass.GetType().GetMethods();
var sampleMethod = methods.FirstOrDefault(method => method.Name == nameof(sampleClass.SampleMethod));
var sampleAttribute = Attribute.GetCustomAttribute(sampleMethod, typeof(SampleAttribute)) as SampleAttribute;
return sampleAttribute.Text;
}
Or even pass the method as the parameter:
var sampleClass = new SampleClass();
ExtractSampleAttributeValue(sampleClass.SampleMethod);
private static string ExtractSampleAttributeValue(Action sampleMethod)
{
var sampleAttribute = Attribute.GetCustomAttribute(sampleMethod.Method, typeof(SampleAttribute)) as SampleAttribute;
return sampleAttribute.Text;
}

C# Dictionary with Named/Labeled Types

I've searched just about everywhere and not even sure it's possible, but what the hey, I thought I would see what you C# wizards might have for a solution or workaround.
TL;DR:
I have a multi-dimensional collection using C# dictionaries and want to indicate what each string in the dictionary is for, something like this:
private Dictionary<string: Area, Dictionary<string: Controller, string: Action>> ActionCollection;
Which of-course does not work. For now I'm just commenting the dictionary.
Suggestions, thoughts, ideas?
You cannot do that, but you could add a summary.
For example:
/// <summary>
/// Dictionary<Area, Dictionary<Controller, Action>>
/// </summary>
private Dictionary<string, Dictionary<string, string>> ActionCollection;
These comments will show up in the intellisense.
Or:
If you want to extract info with reflection, you could use custom attributes
If it is just for readability, you could create aliases for it:
using Area = System.String;
using Controller = System.String;
using Action = System.String;
namespace MyApp
{
public class MyClass
{
private Dictionary<Area, Dictionary<Controller, Action>> ActionCollection;
}
}
But intellisense will show string
#MMM says about invalid xml, you can do this:
/// <summary>
/// Dictionary<Area, Dictionary<Controller, Action>>
/// </summary>
Make a class that pairs the key or the value with the annotation:
class AnnotatedVal {
public string Val {get;}
public string Annotation {get;}
public AnnotatedVal(string val, string annotation) {
// Do null checking
Val = val;
Annotation = annotation;
}
public bool Equals(object obj) {
var other = obj as AnnotatedVal;
return other != null && other.Val == Val && other.Annotation == Annotation;
}
public int GetHashCode() {
return 31*Val.GetHashCode() + Annotation.GetHashCode();
}
}
private Dictionary<AnnotatedVal,Dictionary<AnnotatedVal,AnnotatedVal>> ActionCollection;
Now you can use AnnotatedVal in your dictionaries to assure segregation:
ActionCollection.Add(new AnnotatedVal("hello", "Area"), someDictionary);
if (ActionCollection.ContainsKey(new AnnotatedVal("hello", "Area"))) {
Console.WriteLine("Yes");
} else {
Console.WriteLine("No");
}
if (ActionCollection.ContainsKey(new AnnotatedVal("hello", "Controller"))) {
Console.WriteLine("Yes");
} else {
Console.WriteLine("No");
}
The above should produce
Yes
No
because AnnotatedVal("hello", "Area") and AnnotatedVal("hello", "Controller") use different annotations.
You could wrap each string in it's own class. Then the declaration and intellisense will be descriptive:
public class Area
{
public string area { get; set; }
public override string ToString()
{
return area;
}
}
public class Controller
{
public string controller { get; set; }
public override string ToString()
{
return controller;
}
}
public class Action
{
public string action { get; set; }
public override string ToString()
{
return action;
}
}
private Dictionary<Area, Dictionary<Controller, Action>> ActionCollection;
It's possible by using Tuple Field Names within List:
private List<(string Area, List<(string Controller, string Action)>)> ActionCollection;
That's feature from C# 7.0 or from .NET 4.3 by importing System.ValueTuple nuget.

Manage a list of Constants

In several projects, we have a list of constant values in the database. These each have a table, name, and a GUID value. For example a Ticket Status table might have 3 values, "Open", "Closed" and "Hold". In our C# code a framework generates a C# file, as follows.
public class TicketStatus {
public static Guid Open = new Guid( "7ae15a71-6514-4559-8ea6-06b9ddc7a59a");
public static Guid Closed = new Guid( "41f81283-57f9-4bda-a03c-f632bd4d1628");
public static Guid Hold = new Guid( "41bcc323-258f-4e58-95be-e995a78d2ca8");
}; // end of TicketStatus
This allows us to write some clean(ish) code that sets ticket status as follows
ticket.strStatus = TicketStatus.Open.ToString();
While this works:
- It produces pretty clean C# code that's easy to ready and maintain
- It's supported by Intellisense
it's still clumsy, in that
- We have to continually convert to string for many operations
- The use of GUIDs seems like overkill.
- We cannot write a "normal" switch statement
// This won't compile
switch( strStatus ) {
case TicketStatus.Open:
case TicketStatus.Closed:
// do some stuff.
break;
}
The code was originally implemented with a bunch of GUIDs, to manage the case when a database would return the values in all upper case.
The question: What's the best way to code these constant values, so that it supports IntelliSense and switch statements?
Thanks Kirk,
Here's the string solution that I'm using.
public static class TicketStatus {
public const string Open = "7ae15a71-6514-4559-8ea6-06b9ddc7a59a";
public const string Closed = "41f81283-57f9-4bda-a03c-f632bd4d1628";
public const string Hold = "41bcc323-258f-4e58-95be-e995a78d2ca8";
}; // end of TicketStatus
string strTemp = TicketStatus.Open;
switch (strTemp) {
case TicketStatus.Open:
strTemp = "Jackpot";
break;
}
Preamble
I do really think, that you should stick to this for as long as you can.
public static class TicketStatus {
public const string Open = "7ae15a71-6514-4559-8ea6-06b9ddc7a59a";
public const string Closed = "41f81283-57f9-4bda-a03c-f632bd4d1628";
public const string Hold = "41bcc323-258f-4e58-95be-e995a78d2ca8";
}; // end of TicketStatus
If you want some magic :)
There is a solution, that nobody has mentioned here. You can use attributes to assign custom values to enumerations. You need to define an attribute and some helper class:
[AttributeUsage(AttributeTargets.Field)]
public class GuidValue : Attribute
{
public Guid Guid
{
get;
private set;
}
public GuidValue(Guid guid)
{
this.Guid = guid;
}
public GuidValue(string stringGuid)
{
this.Guid = new Guid(stringGuid);
}
}
public static class GuidBackedEnums
{
private static Guid GetGuid(Type type, string name)
{
return type.GetField(name).GetCustomAttribute<GuidValue>().Guid;
}
public static Guid GetGuid(Enum enumValue)
{
Type type = enumValue.GetType();
if (!type.IsEnum)
throw new Exception();
return GetGuid(type, enumValue.ToString());
}
public static T CreateFromGuid<T>(Guid guid)
{
Type type = typeof(T);
if (!type.IsEnum)
throw new Exception();
foreach (var value in Enum.GetValues(type))
{
if (guid == GetGuid(type, value.ToString()))
return (T)value;
}
throw new Exception();
}
}
And then you can use it in the following way:
enum TicketStatus
{
[GuidValue("7ae15a71-6514-4559-8ea6-06b9ddc7a59a")]
Open,
[GuidValue("41f81283-57f9-4bda-a03c-f632bd4d1628")]
Closed,
[GuidValue("41bcc323-258f-4e58-95be-e995a78d2ca8")]
Hold
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine(GuidBackedEnums.CreateFromGuid<TicketStatus>(new Guid("41f81283-57f9-4bda-a03c-f632bd4d1628")));
Console.WriteLine(GuidBackedEnums.GetGuid(TicketStatus.Hold));
}
}
And, of course, TicketStatus is an ordinary enum. So you can use it in switch statements.
I would use a java-like enum and some reflection. Here's an example C# implementation. It my not work with a switch, but it will quickly identify for you the required object.
using System;
using System.Reflection;
using System.Linq;
public class TicketStatus
{
private string _guid;
private TicketStatus(string guid)
{
_guid = guid;
}
public string GuidValue {get {return _guid; } }
public static readonly TicketStatus Open = new TicketStatus("7ae15a71-6514-4559-8ea6-06b9ddc7a59a");
public static readonly TicketStatus Closed = new TicketStatus("41f81283-57f9-4bda-a03c-f632bd4d1628");
public static readonly TicketStatus Hold = new TicketStatus("41bcc323-258f-4e58-95be-e995a78d2ca8");
//Reads all static readonly fields and selects the one who has the specified GUID
public static TicketStatus Identify(string guid)
{
var ticket = typeof(TicketStatus).GetFields()
.Where(x => (x.IsStatic == true) && (x.IsInitOnly == true) )
.Select(x => x.GetValue(null))
.SingleOrDefault(x => (x as TicketStatus).GuidValue == guid)
as TicketStatus;
return ticket;
}
}
public class Program
{
public static void Main()
{
var guid = "7ae15a71-6514-4559-8ea6-06b9ddc7a59a";
var ticket = TicketStatus.Identify(guid);
if(ticket != null)
{
Console.WriteLine(ticket.GuidValue + " found");
}
else
{
Console.WriteLine("unknown ticket");
}
}
}
try this
public static Guid Open = new Guid("7ae15a71-6514-4559-8ea6-06b9ddc7a59a");
public static Guid Closed = new Guid("41f81283-57f9-4bda-a03c-f632bd4d1628");
public static Guid Hold = new Guid("41bcc323-258f-4e58-95be-e995a78d2ca8");
public enum Status1
{
Open,
Close,
Hold
}
public static Dictionary<Guid, Status1> Dic = new Dictionary<Guid, Status1>()
{
{Open , Status1.Open},
{Closed , Status1.Close},
{Hold , Status1.Hold}
};
and then
var a = TicketStatus.Closed;
var label = TicketStatus.Dic.FirstOrDefault(e => e.Key == a).Value;
switch (label)
{
case TicketStatus.Status1.Close:
}
to keep your code more readable

.Net 4.0 Optimized code for refactoring existing "if" conditions and "is" operator

I have following C# code. It works fine; but the GetDestination() method is cluttered with multiple if conditions by using is operator.
In .Net 4.0 (or greater) what is the best way to avoid these “if” conditions?
EDIT: Role is part of the business model, and the destination is purely an artifact of one particular application using that business model.
CODE
public class Role { }
public class Manager : Role { }
public class Accountant : Role { }
public class Attender : Role { }
public class Cleaner : Role { }
public class Security : Role { }
class Program
{
static string GetDestination(Role x)
{
string destination = #"\Home";
if (x is Manager)
{
destination = #"\ManagerHomeA";
}
if (x is Accountant)
{
destination = #"\AccountantHomeC";
}
if (x is Cleaner)
{
destination = #"\Cleaner";
}
return destination;
}
static void Main(string[] args)
{
string destination = GetDestination(new Accountant());
Console.WriteLine(destination);
Console.ReadLine();
}
}
REFERENCES
Dictionary<T,Delegate> with Delegates of different types: Cleaner, non string method names?
Jon Skeet: Making reflection fly and exploring delegates
if-else vs. switch vs. Dictionary of delegates
Dictionary with delegate or switch?
Expression and delegate in c#
Having virtual property which would be overriden in derived classes should do the trick:
class Role
{
public virtual string Destination { get { return "Home"; } }
}
class Manager : Role
{
public override string Destination { get { return "ManagerHome;"; } }
}
class Accountant : Role
{
public override string Destination { get { return "AccountantHome;"; } }
}
class Attender : Role
{
public override string Destination { get { return "AttenderHome;"; } }
}
class Cleaner : Role
{
public override string Destination { get { return "CleanerHome;"; } }
}
class Security : Role { }
I didn't make the property abstract, to provide default Home value when it's not overriden in derived class.
Usage:
string destination = (new Accountant()).Destination;
Console.WriteLine(destination);
Console.ReadLine();
Here's one option:
private static readonly Dictionary<Type, string> DestinationsByType =
new Dictionary<Type, string>
{
{ typeof(Manager), #"\ManagerHome" },
{ typeof(Accountant), #"\AccountantHome" },
// etc
};
private static string GetDestination(Role x)
{
string destination;
return DestinationsByType.TryGetValue(x.GetType(), out destination)
? destination : #"\Home";
}
Note:
This doesn't cope with null parameters. It's not clear whether or not you actually need it to. You can easily add null handling though.
This doesn't copy with inheritance (e.g. class Foo : Manager); you could do that by going up the inheritance hierarchy if necessary
Here's a version which does deal with both of those points, at the cost of complexity:
private static string GetDestination(Role x)
{
Type type = x == null ? null : x.GetType();
while (type != null)
{
string destination;
if (DestinationsByType.TryGetValue(x.GetType(), out destination))
{
return destination;
}
type = type.BaseType;
}
return #"\Home";
}
EDIT: It would be cleaner if Role itself had a Destination property. This could either be virtual, or provided by the Rolebase class.
However, it could be that the destination is really not something the Role should concern itself with - it could be that Role is part of the business model, and the destination is purely an artifact of one particular application using that business model. In that sort of situation, you shouldn't put it into Role, as that breaks separation of concerns.
Basically, we can't tell which solution is going to be most suitable without knowing more context - as is so often the way in matters of design.
Approach 1 (Selected): Using dynamic keyword to implement multimethods / double dispatch
Approach 2: Use a dictionary to avoid if blocks as mentioned in Jon Skeet’s answer below.
Approach 3: Use a HashList with delegates if there is condition other than equality (For example, if input < 25). Refer how to refactor a set of <= , >= if...else statements into a dictionary or something like that
Apporach 4: Virtual Functions as mentioned in MarcinJuraszek’s answer below.
MultiMethods / Double Dispatch approach using dynamic keyword
Rationale: Here the algorithm changes based on the type. That is, if the input is Accountant, the function to be executed is different than for Manager.
public static class DestinationHelper
{
public static string GetDestinationSepcificImplm(Manager x)
{
return #"\ManagerHome";
}
public static string GetDestinationSepcificImplm(Accountant x)
{
return #"\AccountantHome";
}
public static string GetDestinationSepcificImplm(Cleaner x)
{
return #"\CleanerHome";
}
}
class Program
{
static string GetDestination(Role x)
{
#region Other Common Works
//Do logging
//Other Business Activities
#endregion
string destination = String.Empty;
dynamic inputRole = x;
destination = DestinationHelper.GetDestinationSepcificImplm(inputRole);
return destination;
}
static void Main(string[] args)
{
string destination = GetDestination(new Security());
Console.WriteLine(destination);
Console.WriteLine("....");
Console.ReadLine();
}
}
This is a strongly typed, imperative language so if statements and type checking are going to happen.
Having said that, have you considered a virtual method on Role that can be overridden to provide a destination string?
A further alternative, a lookup table!
Dictionary<Type, string> paths = new Dictionary<TYpe, string>()
{
{ typeof(Manager), #"\ManagerHomeA" }
{ typeof(Accountant), #"\AccountantHomeC" }
{ typeof(Cleaner), "Cleaner" }
}
string path = #"\Home";
if(paths.ContainsKey(x.GetType())
path = paths[x];
One way to do it would be to use a map instead of an if:
//(psuedocode)
private Dictionary<Type, string> RoleMap;
void SomeInitializationCodeThatRunsOnce()
{
RoleMap.Add(typeof(Manager), #"\ManagerHome");
RollMap.Add(typeof(Accountant), #"\AccountantHome");
// ect...
}
string GetDestination(Role x)
{
string destination;
if(!RoleMap.TryGet(x.GetType(), out destination))
destination = #"\Home";
return destination;
}
Further reading: http://www.hanselman.com/blog/BackToBasicsMovingBeyondForIfAndSwitch.aspx
Role should have a virtual function that would return destination:
public virtual string GetDestination()
{
return "Home";
}
And all the classes should override this function and return the correct string. Then in the code you would have:
var role = new Accountant();
string destination = role.GetDestination();
I hope that helps. There may be typos, I am writing from head.
you can either use an interface definition or an abstract method / property
with interface:
public interface IDestinationProvider
{
sting Destination { get; }
}
string GetDestination(Role role)
{
var provider = role as IDestinationProvider;
if (provider != null)
return provider.Destination;
return "Default";
}
with an abstract base class
abstract class Role
{
public abstract string GetDestination();
}
class Manager : Role
{
public virtual string GetDestination() { return "ManagerHomeA"; }
}
string GetDestination(Role role)
{
return #"\" + role.GetDestination();
}
or with attributes:
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class DestinationAttribute : Attribute
{
public DestinationAttribute() { this.Path = #"\Home"; }
public string Path { get; set; }
}
[Destination(Path = #"\ManagerHome")]
public class Manager : Role { }
string GetDestination(Role role)
{
var destination = role.GetType().GetCustomAttributes(typeof(DestinationAttribute), true).FirstOrDefault();
if (destination != null)
return destination.Path;
return #"\Home";
}

On-the-fly fields from Static Reflection?

I've been studying up on static reflection with LINQ expressions - very cool!
One thought I had - is it possible for one class to 'generate' fields on one class based on static reflection done on another class? I'm thinking specifically of the Builder pattern I've seen here many times. I would like to do a fluent-nhibernate-style property registration that 'generates' fields on the builder that match the class I want to build. Soemthing like this:
public class Color
{
private Color()
{
}
public string Name { get; private set; }
public class Builder : BuilderBase<Color>
{
public Builder()
{
Property(x => x.Name);
}
public Build()
{
return built_up_color;
}
}
}
and support constructor syntax like this:
Color c = new Color.Builder() { Name = "Red" }.Build();
The point of all this is to reduce the number of times I have to repeat defining the properies of Color. I played with this:
public class Color
{
private Color()
{
}
public string Name { get; private set; }
public class Builder
{
private Color _color = new Color();
public string Name
{
get { return _color.Name; }
set { _color.Name = value; }
}
public Build()
{
return _color;
}
}
}
which certainly works AND lists the properties the same # of times but feels wordier and less flexible. It seems like I should be able to do something anonymous-type-y here?
Worth pointing out that Having a class called Color clashing with the System.Drawing.Color is probably a bad idea.
It is very likely to lead to confusion in others (worse still System.Drawring.Color has value semantics whereas your class has reference semantics which can lead to further confusion)
I would point out that what you really want is Named Optional Arguments. I would suggest that putting in cumbersome Builder classes now will be more effort and made it more painful to move to these once you get to c# 4.0. Instead make the constructors that are required (or if need be to avoid type signature collisions static factory methods on the class)
I think it's impossible, you can't generate members except by declaring them explicitly. Bite the bullet and declare a constructor for Color.
PS: I think static reflection is a misnomer, the only thing that's static is the lookup of the member you want to reference — a good thing as far as it goes, but that's not very far.
less code to write but using reflection to set the values.
The trick is to use collection initializers. it is typesafe.
public class Color
{
private Color()
{
}
public string Name { get; private set; }
public int Prop2 { get; private set; }
public class Builder : Builder<Color>
{
public Builder()
{
// possible
_instance.Name = "SomeDefaultValue";
}
}
}
class Builder<T> : IEnumerable<string>
{
protected T _instance = Activator.CreateInstance(typeof(T));
public void Add<TProperty>(Expression<Func<T, TProperty>> prop, TProperty value)
{
StaticReflection.GetPropertyInfo(prop).SetValue(_instance, value, null);
}
public static implicit operator T(Builder<T> builder)
{
return builder.Build();
}
public T Build()
{
return _instance;
}
IEnumerator<string> IEnumerable<string>.GetEnumerator()
{
// e.g. return iterator over the property names
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable<string>)this).GetEnumerator();
}
}
and call syntax
var color = new Color.Builder
{
{ x => x.Name, "foo" },
{ x => x.Prop2, 5 }
}.Build();
// or
var color = new Builder<Color>
{
{ x => x.Name, "foo" },
{ x => x.Prop2, 5 }
}.Build();
// or
Color color = new Builder<Color>
{
{ x => x.Name, "foo" },
{ x => x.Prop2, 5 }
};

Categories

Resources