Behaviour to simulate an enum implementing an interface - c#

Say I have an enum something like:
enum OrderStatus
{
AwaitingAuthorization,
InProduction,
AwaitingDespatch
}
I've also created an extension method on my enum to tidy up the displayed values in the UI, so I have something like:
public static string ToDisplayString(this OrderStatus status)
{
switch (status)
{
case Status.AwaitingAuthorization:
return "Awaiting Authorization";
case Status.InProduction:
return "Item in Production";
... etc
}
}
Inspired by the excellent post here, I want to bind my enums to a SelectList with an extension method:
public static SelectList ToSelectList<TEnum>(this TEnum enumObj)
however, to use the DisplayString values in the UI drop down I'd need to add a constraint along the lines of
: where TEnum has extension ToDisplayString
Obviously none of this is going to work at all with the current approach, unless there's some clever trick I don't know about.
Does anyone have any ideas about how I might be able to implement something like this?

Is there a compelling reason to use an enum here?
When you start jumping through crazy hoops to use enums, it might be time to use a class.
public class OrderStatus
{
OrderStatus(string display) { this.display = display; }
string display;
public override string ToString(){ return display; }
public static readonly OrderStatus AwaitingAuthorization
= new OrderStatus("Awaiting Authorization");
public static readonly OrderStatus InProduction
= new OrderStatus("Item in Production");
public static readonly OrderStatus AwaitingDispatch
= new OrderStatus("Awaiting Dispatch");
}
You consume it the same as an enum:
public void AuthorizeAndSendToProduction(Order order, ProductionQueue queue)
{
if(order.Status != OrderStatus.AwaitingAuthorization)
{
Console.WriteLine("This order is not awaiting authorization!");
return;
}
order.Status = OrderStatus.InProduction;
queue.Enqueue(order);
}
The string representation is built-in, and all you need is ToString().

Of course, you can use the DisplayAttribute to annotate your Enums.
enum OrderStatus
{
[Display(Description="Long Desc", Name="Awaiting Authorization", ShortName="Wait Auth")]
AwaitingAuthorization,
[Display(Description="...", Name="...", ShortName="...")]
InProduction,
[Display(Description="...", Name="...", ShortName="...")]
AwaitingDespatch
}
You can also opt to create an extension method taking any enumeration value and returning its display name based on the attribute set to it to tidy up the displayed values in the UI, as follows:
public static class EnumExtensions
{
public static string ToName(this Enum enumValue)
{
var displayAttribute = enumValue.GetType()
.GetMember(enumValue.ToString())[0]
.GetCustomAttributes(false)
.Select(a => a as DisplayAttribute)
.FirstOrDefault();
return displayAttribute?.Name ?? enumValue.ToString();
}
}
With
public enum Test
{
[Display(Name="AAA")]
a,
b
}
Code:
Console.WriteLine(Test.a.ToName());
Console.WriteLine(Test.b.ToName());
Results
AAA
b
I want to bind my enums to a SelectList with an extension method:
For type safety, I wouldn't use an extension methods, but instead a static class that deals with the Enum type:
Pre C# 7.3 version. Since Enum is not a valid type constraint prior to 7.3 (and it would cause a compile-time exception), you'll end up by considering that enums are value types and they implement some interfaces, in order to restrict the type parameter as close to Enum as possible.
public static class Enums<TEnum> where TEnum : struct, IComparable, IFormattable, IConvertible
{
static Enums()
{
if (!typeof(TEnum).IsEnum)
{
throw new InvalidOperationException();
}
}
}
C# 7.3+ version, with compile time checking... yay!
public static class Enums<TEnum> where TEnum : Enum
{
}
GetValues Method for the class:
public static IEnumerable<TEnum> GetValues(bool includeFirst)
{
var result = ((TEnum[])Enum.GetValues(typeof(TEnum))).ToList();
if (!includeZero)
result = result.Where(r => r != default).ToList();
return result;
}
If you follow Enum Guidelines and include the Default (zero) value, we can ignore it (sometimes we want to display the value like "None Selected" and sometimes we don't "Invalid Selection").
Then we can add another method:
public static IEnumerable<string> GetNames(bool includeFirst)
{
var result = GetValue(includeFirst)
.Select(v => v.ToName())
.ToList();
return result;
}

Instead of using "ToDisplayString", simply override ToString() of your enum. So if an enum overrides it it will take it, otherwise it will take the default ToString behavior (in ToSelectList).

If you just need to use relatively tiny enumerate classes that have no more than an explicit casting operator, ToString and do not take other usability for the special ones about enum on System and its derived namespaces, then the following example could be a solution:
namespace MyNamespace {
public abstract class EnumerateClass<Type, InheritingClass> : IEquatable<InheritingClass>
where Type : IEquatable<Type>
where InheritingClass : EnumerateClass<Type, InheritingClass> {
internal readonly Type Identifier;
protected EnumerateClass (Type identifier) {
this.Identifier = identifier;
}
public bool Equals(InheritingClass obj)
=> this.Identifier.Equals(obj.Identifier);
public static explicit operator Type(EnumerateClass<Type, InheritingClass> obj)
=> obj.Identifier;
}
public sealed class MyNumber : EnumerateClass<int, MyNumber> {
private MyNumber(int identifier) : base(identifier) { }
public static readonly MyNumber None = new Number(0);
public static readonly MyNumber One = new Number(1);
public static readonly MyNumber Two = new Number(2);
...
public override string ToString() {
switch (this.Identifier) {
case 0: return "None";
case 1: return "One";
case 2: return "Two";
...
}
}
}
}

You could do this:
public static string ToOrderStatusDisplayString(this Enum status)
{
switch ((OrderStatus)status)
{
...
}
}
Then restrict TEnum to Enum: where TEnum : System.Enum
Of course, that way you get a bunch of methods on the Enum itself and lose type safety.

Related

Return instance of deriving class from abstract generic method

What I want to do here is a bit hard to describe. My current needs require that I have an enum type that can implement an interface. While not the prettiest solution, this is what I came up with;
public class EnumClass<T> where T : Enum
{
public T Value { get; }
public string Name { get; }
public EnumClass(T enumValue)
{
Value = enumValue;
Name = Enum.GetName(typeof(T), enumValue);
}
public static EnumClass<T> Parse(string name)
{
return new EnumClass<T>((T)Enum.Parse(typeof(T), name));
}
}
Here is an example implementation:
public class AnimalTypes : EnumClass<AnimalTypesEnum>, IMyEnumInterface
{
public AnimalTypes (AnimalTypesEnum value) : base(value) { }
}
public enum AnimalTypesEnum
{
[Description("Cat")]
CAT,
[Description("Dog")]
DOG,
[Description("Horse")]
HORSE,
[Description("Bear")]
BEAR
}
When I call Parse statically on an inheritor, I have to manually cast the result back to the inheritor type from the base type, since Parse returns a generic EnumClass<T> object.
ex.
AnimalTypes dog = (AnimalTypes)AnimalTypes.Parse("DOG");
My question essentially is, is there any way to write Parse such that it returns the type of the inheritor, and not the base class? I'd also like to be able to mark EnumClass<T> abstract, but if I try doing so now, the compiler will not compile Parse, stating that I cannot create an abstract instance of type EnumClass<T> with which to return.
You can use a curiously recursive template pattern, but it requires default constructors and feels odd. Normally if things get this convoluted it's worth asking if your requirements can be restructured so that it's not so complicated, but it's hard to know if that's possible with the details given. That said, this may be as close to what you are asking for that you can get.
There isn't a way to specify that a method return the derived type, but you can specify the return type using a generic type. Below is the EnumClass, but modified to take two generic types. The first type is the enum type like before, but the second is for specifying the derived type (hence the recursive part of the template).
public abstract class EnumClass<T, TDerived>
where T : Enum where TDerived : EnumClass<T, TDerived>, new()
{
protected EnumClass()
{
}
protected EnumClass(T enumValue)
{
Value = enumValue;
}
private T _value = default(T);
public T Value
{
get => _value;
init => _value = value;
}
private string _name = null;
public string Name
{
get
{
_name = _name ?? Enum.GetName(typeof(T), Value);
return _name;
}
}
public static TDerived Parse(string name)
{
var enumValue = (T)Enum.Parse(typeof(T), name);
return new TDerived() {Value = enumValue};
}
}
Then, a derived type using this EnumClass would look like this, where the second generic type recursively refers to itself, which means that the static Parse method in the EnumClass will return a type AnimalTypes.
public class AnimalTypes : EnumClass<AnimalTypesEnum, AnimalTypes>
{
public AnimalTypes(): base()
{
}
public AnimalTypes(AnimalTypesEnum value): base(value)
{
}
}
In use, it would look like this
//because we are required to have public default constructors, it's possible
//to have a "default" AnimalTypes class that would be similar to constructing
//a "new AnimalTypes(default(AnimalTypesEnum));"
var defaultType = new AnimalTypes();
//this will output "CAT, CAT"
Console.WriteLine($"{defaultType.Value}, {defaultType.Name}");
//Since we are using init, you can initialize the value using this format
//instead of using the constructor
var horseType = new AnimalTypes() {Value = AnimalTypesEnum.HORSE};
//this will output "HORSE, HORSE"
Console.WriteLine($"{horseType.Value}, {horseType.Name}");
//normal constructor
var dogType = new AnimalTypes(AnimalTypesEnum.DOG);
//this will output "DOG, DOG"
Console.WriteLine($"{dogType.Value}, {dogType.Name}");
//static parser will return a type of AnimalTypes
var bearType = AnimalTypes.Parse("BEAR");
//this will output "BEAR, BEAR"
Console.WriteLine($"{bearType.Value}, {bearType.Name}");
You need to add another type param, in order to parametrize the return value type of Parse and enable derived/inherited types being created.
Usage:
var bear = EnumClass<AnimalTypesEnum>.Parse<AnimalTypes>("BEAR");
//AnimalTypesEnum unchanged
//AnimalTypes unchanged
public abstract class EnumClass<TEnum> where TEnum : Enum
{
public TEnum Value { get; }
public string Name { get; }
protected EnumClass(TEnum enumValue)
{
Value = enumValue;
Name = Enum.GetName(typeof(TEnum), enumValue);
}
public static TEnumClass Parse<TEnumClass>(string name)
where TEnumClass : EnumClass<TEnum>
{
//TODO: try/catch
/* Contract: the derived class must have a public constructor
that takes 1 arg of its enum type.
Generic constraints don't support ctors with args, so we need reflection here... */
return (TEnumClass)Activator.CreateInstance(
typeof(TEnumClass), Enum.Parse(typeof(TEnum), name));
}
}

java enums vs C# enums - missing features

in java I could easily describe an enum with aditional data.
I could describe it something like this
public enum OperatorType
{
GreaterOrEqual (">=", "GreaterOrEqual"),
Greater (">" ,"Greater"),
Less ("<", "Less"),
LessOrEqual ("<=", "LessOrEqual"),
Equal ("==", "Equal"),
Between ("Between", "Between"),
Around ("Around","Around");
private final String symbol;
private final String name;
private OperatorType(final String symbol, final String name) {
this.symbol = symbol;
this.name = name;
}
}
And then add a static method that iterates over values(), adds all data to a hashmap and allow to retrieve from the map full enum data by one of its attriburtes as a key.
In brief, enum is a very developed type in java.
Now,
moving to c#, what are my options?
I want to hold an enum with its attributes, load it to a map, and retreive by key when I need. Do I have anything to assist (like, a singletone for each enum - which is not a good idea).
Thanks.
I would just create a class with public static readonly instances of each type and ditch enums altogether. You can use them as dictionary keys or do whatever you like. If you still intend to map them to an underlying data type (int) then you can create implicit operators for that too.
public class OperatorType
{
private static readonly Dictionary<int, OperatorType> OperatorMapping = new Dictionary<int, OperatorType>();
public static readonly OperatorType GreaterOrEqual = new OperatorType(0, ">=", "GreaterOrEqual");
public static readonly OperatorType Greater = new OperatorType(1, ">", "Greater");
public readonly String symbol;
public readonly String name;
private readonly int underlyingValue;
private OperatorType(int underlyingValue, string symbol, string name) {
this.underlyingValue = underlyingValue;
OperatorMapping[underlyingValue] = this;
this.symbol = symbol;
this.name = name;
}
public static implicit operator int(OperatorType operatorType)
{
return operatorType.underlyingValue;
}
public static implicit operator OperatorType(int value)
{
return OperatorMapping[value];
}
}
Sample usage:
Dictionary<OperatorType, string> operators = new Dictionary<OperatorType, string>();
operators.Add(OperatorType.GreaterOrEqual, "Greater or equal");
Console.WriteLine(operators[OperatorType.GreaterOrEqual]); //"Greater or equal"
OperatorType operatorType = 1;
Console.WriteLine(operatorType.name); //"Greater"
If you don't care about an underlying value, don't include it. Also consider whether or not the Dictionary mapping should be threadsafe for your usage. You can also expose a static IEnumerable<OperatorType> (or other collection) to get all operators defined if you want.
EDIT: On second thought, explicit operators are possibly preferable instead of implicit, both to conform with typical .NET best practices and to better match typical enum conversions.
The most convinient workaround might be to create an extension method to your enum type, and return the associated symbols.
Something like this:
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
tester t = tester.x;
t.testenums();
Console.ReadKey();
}
}
public static class ext
{
public static void testenums(this tester x)
{
Console.WriteLine(x.ToString());
}
}
public enum tester
{
x,
y
}
}
Of course you can write a more complex extension method, with return value, etc, this is just an example how to do it.
You can create an attribute:
public class EnumKeyAttribute : Attribute
{
public string Key { get; set; }
public string Description { get; set; }
public EnumKeyAttribute(string key, string description)
{
this.Key = key;
this.Description = description;
}
}
Then apply it to your enum
public enum OperatorType
{
[EnumKey(">=", "GreaterOrEqual")]
GreaterOrEqual,
[EnumKey(">", "Greater")]
Greater,
[EnumKey("<", "Less")]
Less,
[EnumKey("<=", "LessOrEqual")]
LessOrEqual,
[EnumKey("==", "Equal")]
Equal,
[EnumKey("Between", "Between")]
Between,
[EnumKey("Around", "Around")]
Around
}
To get the attribute data you can use reflection. Below is an example of getting the attribute for "Less"
MemberInfo memberInfo = typeof(OperatorType).GetMember(OperatorType.Less.ToString()).FirstOrDefault();
if(memberInfo != null)
{
EnumKeyAttribute attribute = (EnumKeyAttribute)memberInfo.GetCustomAttributes(typeof(EnumKeyAttribute), false).FirstOrDefault();
Console.WriteLine(attribute.Key);
Console.WriteLine(attribute.Description);
}
But because these enums are not created at runtime you can increase your efficiency by creating a static method that looks up the value in a dictionary. Do this as an extension method for ease of use
public static class KeyFinder
{
private static Dictionary<OperatorType, EnumKeyAttribute> lookupTable =
new Dictionary<OperatorType, EnumKeyAttribute>();
public static EnumKeyAttribute GetKey(this OperatorType type)
{
if (lookupTable.ContainsKey(type))
{
return lookupTable[type];
}
MemberInfo memberInfo = typeof(OperatorType).GetMember(type.ToString()).FirstOrDefault();
if (memberInfo != null)
{
EnumKeyAttribute attribute = (EnumKeyAttribute)memberInfo.GetCustomAttributes(typeof(EnumKeyAttribute), false).FirstOrDefault();
if (attribute != null)
{
lookupTable.Add(type, attribute);
return attribute;
}
}
// add a null value so next time it doesn't use reflection only to find nothing
lookupTable.Add(type, null);
return null;
}
}
So now to get the values you simply do the following:
OperatorType.Less.GetKey().Key
OperatorType.Less.GetKey().Description
Just be careful of null reference exceptions (since it will return null if it can't find an attribute). If you want to find by key you can simply create other extension methods that use the string value as the key.
C# doesn't really have the same feature. However there are several possibilities to get really close (and potentially more flexible as well).
Sticking to regular enums, you could use attributes to enrich with extra information. Of course, this requires reflection to work with that
public enum OperatorType
{
[DisplayName(">=")]
GreaterOrEqual,
// ...
}
There are several patterns to work with this, e.g. http://www.codeproject.com/Articles/28087/DisplayNameAttribute-for-Enumerations, google for more.
Another approach can be to enhance your enumeration types using regular classes:
public class OperatorType
{
public static OperatorType GreaterOrEqual = new OperatorType(">=", "GreaterOrEqual");
// ...
string symbol;
string name;
private OperatorType(string symbol, string name)
{
this.symbol = symbol;
this.name = name;
}
}
This article describes some other ways to work with enum-like types in C#
If you really need the functionality of Java-style enums in C#, I see three reasonable ways to implement it:
Use a C# enum and a static class of helper methods. You lose type safety, but this is an otherwise very workable solution.
Use a C# enum and a set of extension methods. Probably the most idiomatic C# solution, but you still have to deal with the loss of type safety (your extension methods should be able to cope with out-of-range values, even if only by throwing an exception).
Use the type-safe enum pattern that was common in Java before the language gained the enum keyword in Java 5. If you have non-trivial logic for each enum value, this would be my preference.

C# Enum return string with breaks

I need my enum to return a specific string, but I can't work out how to make it return a string with breaks in it without having a method to do the conversion. Is it possible to make LicenseTypes.DISCOUNT_EARLY_ADOPTER return DISCOUNT EARLY-ADOPTER without the helper method?
// All license types
public enum LicenseTypes
{
DISCOUNT,
DISCOUNT_EARLY_ADOPTER,
COMMERCIAL,
COMMERCIAL_EARLY_ADOPTER
}
// Convert enum to correct string
public static string LicenseTypeToString(LicenseTypes Enum)
{
if (Enum == LicenseTypes.COMMERCIAL)
return "COMMERCIAL";
else if (Enum == LicenseTypes.COMMERCIAL_EARLY_ADOPTER)
return "COMMERCIAL EARLY-ADOPTER";
else if (Enum == LicenseTypes.DISCOUNT)
return "DISCOUNT";
else if (Enum == LicenseTypes.DISCOUNT_EARLY_ADOPTER)
return "DISCOUNT EARLY-ADOPTER";
else
return "ERROR";
}
Firstly, a separate option from a helper method is simply to have a Dictionary<LicenseTypes, string> which you populate once. That would probably be the simplest approach, to be honest:
private static readonly Dictionary<LicenseTypes, string> LicenseDesciptions =
new Dictionary<LicenseTypes, string>
{
{ LicenseTypes.COMMERCIAL, "COMMERCIAL" },
{ LicenseTypes.COMMERCIAL_EARLY_ADOPTER, "COMMERCIAL EARLY-ADOPTER" },
{ LicenseTypes.DOMESTIC, "DOMESTIC" },
{ LicenseTypes.DOMESTIC_EARLY_ADOPTER, "DOMESTIC EARLY-ADOPTER" },
};
(As noted in comments, another alternative is a switch/case... but I personally prefer this way, as effectively you've got a data mapping, so it makes sense to use a data structure rather than an execution flow structure. It also means you can swap out dictionaries for different languages etc if you want.)
Secondly, one option would be to decorate each enum value with a [Description] attribute (or your own attribute if you want), and find that out with reflection - Unconstrained Melody has an extension method which can do that very easily:
// Throws ArgumentOutOfRangeException if the licenseType value isn't defined
// or doesn't have a description.
string description = licenseType.GetDescription();
Also, following .NET naming conventions it should be:
public enum LicenseType // Singular as it's not a Flags enum
{
Discount,
DiscountEarlyAdopter,
Commercial,
CommercialEarlyAdopter
}
A little reflection, and Attribute magic, and this should just answer it :)
Getting attributes of Enum's value
Might also make it an extension method.
here's how it should look (also added generics):
public static class MyExtensionsClass
{
public static string ToDescriptionString<T>(this T val)
where T : struct, IConvertible
{
if (typeof(T).IsEnum)
{
var type = val.GetType();
var memInfo = type.GetMember(val.ToString());
var attributes = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
return ((DescriptionAttribute)attributes[0]).Description;
}
return ""; //all paths must return a value
}
}
public enum LicenseTypes
{
[Description("DISCOUNT")]
DISCOUNT,
[Description("DISCOUNT EARLY-ADOPTER")]
DISCOUNT_EARLY_ADOPTER,
[Description("COMMERCIAL")]
COMMERCIAL,
[Description("COMMERCIAL EARLY-ADOPTER")]
COMMERCIAL_EARLY_ADOPTER
}
Thank you, guys that wrote these:
Enhance enums using extension methods
Create Generic method constraining T to an Enum
Good luck!
While it doesn't eliminate the helper method, note that in your case you could just special-case the values that you can't get using ToString:
switch (Enum) {
case LicenseTypes.COMMERCIAL_EARLY_ADOPTER:
return "COMMERCIAL EARLY-ADOPTER";
case LicenseTypes.DISCOUNT_EARLY_ADOPTER:
return "DISCOUNT EARLY-ADOPTER";
default
return Enum.ToString();
}
I use this from Google's dotnet client - StringValueAttribute.cs
and Utilities.cs
public enum LicenseType
{
[StringValue("DISCOUNT")] Discount,
[StringValue("DISCOUNT EARLY-ADOPTER")] DiscountEarlyAdopter,
[StringValue("COMMERCIAL")] Commercial,
[StringValue("COMMERCIAL EARLY-ADOPTER")] CommercialEarlyAdopter
}
Then you can simply do this:
licenseType.GetStringValue();
Convert to string using "G" format, then replace "_" (underscore) with spaces:
LicensceTypes license = LicenseTypes.COMMERCIAL_EARLY_ADOPTERS;
string licenseDescription = license.ToString("G").Replace('_', ' ');
// licenseDescription = "COMMERCIAL EARLY ADOPTERS"
I think I would use a class to avoid this scenario. :/
public class LicenceType
{
private string name;
public LicenceType(string Name)
{
this.name = Name;
}
public override string ToString()
{
return name;
}
}
public static class LicenceTypes
{
public static LicenceType DISCOUNT = new LicenceType("DISCOUNT");
public static LicenceType DISCOUNT_EARLY_ADOPTER= new LicenceType("DISCOUNT EARLY-ADOPTER");
public static LicenceType COMMERCIAL= new LicenceType("COMMERCIAL");
public static LicenceType COMMERCIAL_EARLY_ADOPTER= new LicenceType("COMMERCIAL EARLY-ADOPTER");
}

Can an enum return a new instance in C#?

Greetings everyone!
I'll try to make my problem simple: I have an enum to select which ObjType I should use (ObjTypeA and ObjTypeB both inherits from ObjType). So I created a method to extend the given enum, in order to return a new instance according to the selected property in the enum, like follows in the code. I think it works more or less like a factory design pattern. So far so good, but eventually, like in the class MyClass, I may attempt to create n instances of ObjTypeA or ObjTypeB, but I'll have to face the if statement everytime I call the GetObjTypeInstance() method. So:
Can an enum return an instance, something like: public enum EObjType { ObjTypeA = new ObjTypeA(), ObjTypeB = new ObjTypeB() }? Actually, it'd be better to append some GetInstance() method to the ObjTypeA and to the ObjTypeB options in the enum. If there's a way to do this, how can I do it? Doing this I'd avoid those if statements every while step.
Is there any other (and better) way to this this (if you understood my problem...)? How?
Thanks in advance!
Follow the example code:
public static class EObjTypeExt
{
public static ObjType GetObjTypeInstance(this EObjType ot)
{
if (ot == EObjType.ObjTypeA)
{
return new ObjTypeA();
}
else if (ot == EObjType.ObjTypeB)
{
return new ObjTypeB();
}
throw new ArgumentOutOfRangeException("unrecognized type!");
}
}
public enum EObjType { ObjTypeA, ObjTypeB }
public class MyClass
{
ObjType[] obj { get; set; }
public MyClass(EObjType otEnum, int n)
{
this.obj = new ObjType[n];
int i = 0;
while (i < n)
{
this.obj[i] = otEnum.GetObjTypeInstance();
i++;
}
}
}
You'll have to byte this apple somewhere.
Maybe replace the if/elseif chain with switch statement, they work great with enums.
Instead of using an enum, I would use a class that looks like an enum:
public class EObjType {
public static readonly EObjType ObjTypeA = new EObjType(() => (ObjType)(new ObjTypeA));
public static readonly EObjType ObjTypeB = new EObjType(() => (ObjType)(new ObjTypeB));
private readonly Func<ObjType> generator;
private EObjType(Func<ObjType> generator) {
this.generator = generator;
}
public ObjType GetInstanceOfObjType() {
return generator();
}
}
You can then use it exactly as you have been the enum.
EObjType otEnum = EObjType.ObjTypeA;
ObjType obj = otEnum.GetInstanceOfObjType();
You need to use a factory or other creational design pattern.
For instance, you could hold a dictionary from enum key to type value to get the desired class type using selected enum value. Then use reflection to create a new instance (object) of received type.
Initialize static dictionary's values using static constructor of factory class. You can enter the values manually or better yet, load possible values from a config file.
I'm not sure that I'd really advocate this approach, but you could call the enum ToString() method, treat that as your class name and use reflection to instantiate an object of that type.
One advantage of this would be that you could reflect and get the type once, then call the constructor n times in your loop.
As Danny Varod points out, a dictionary mapping your enum values to their Types (or to functions that create those types) would allow you to avoid if statements. Since enum is really just an integer underneath, an array would be more memory and time efficient, but readability is probably most important here.
You could create a factory that allows registration of functions that map to your enumeration, you could that use some sort of registration process to register your different enumerations
public class ObjectFactory
{
private readonly Dictionary<MyObjectType, Func<MyObject>> _store = new Dictionary<MyObjectType, Func<MyObject>>();
public void Register<T>(MyObjectType type) where T: MyObject, new()
{
this.Register(type, () => new T());
}
public void Register(MyObjectType type, Func<MyObject> factory)
{
_store.Add(type, factory);
}
public MyObject CreateInstance(MyObjectType type)
{
Func<MyObject> factory;
if(_store.TryGetValue(type, out factory))
{
return factory.Invoke();
}
return null;
}
}
public enum MyObjectType { A, B }
public class MyObject {}
public class MyObjectA : MyObject {}
public class MyObjectB : MyObject {}
Usage as follows
var factory = new ObjectFactory();
factory.Register<MyObjectA>(MyObjectType.A);
factory.Register<MyObjectB>(MyObjectType.B);
var a = factory.CreateInstance(MyObjectType.A);
var b = factory.CreateInstance(MyObjectType.B);
Assert.IsInstanceOf(typeof(MyObjectA), a);
Assert.IsInstanceOf(typeof(MyObjectB), b);
You could use Activator.CreateInstance.
public class ObjType {}
public class ObjTypeA : ObjType {}
public class ObjTypeB : ObjType {}
public enum EObjType { ObjTypeA, ObjTypeB }
public static class EObjTypeExt
{
public static ObjType GetObjTypeInstance( EObjType ot)
{
object o = Activator.CreateInstance(null,ot.ToString());
return (ObjType)o;
}
}

How can I make this code with enumerations generic?

I am creating the wrapper POCO classes for ENUM in Entity Framework 4 as mentioned here. I have created the wrapper for the enum as follows
public class PriorityWrapper
{
private gender _t;
public int Value
{
get
{
return (int)_t;
}
set
{
_t = (gender)value;
}
}
public gender EnumValue
{
get
{
return _t;
}
set
{
_t = value;
}
}
public static implicit operator PriorityWrapper(gender p)
{
return new PriorityWrapper { EnumValue = p };
}
public static implicit operator gender(PriorityWrapper pw)
{
if (pw == null) return gender.Male;
else return pw.EnumValue;
}
}
But I also have other ENUM apart from gender as mentioned above. Can I use generics here so I can use the same code for all ENUM occurrences.
I am new to generics, so need help from experts.
You cannot use enums as generic constraints, instead you can use.
public class EnumWrapper<T>
{
public static int Num = 1;
private T _t;
public T EnumValue
{
get
{
return _t;
}
set
{
_t = value;
}
}
public void Assign<U>(U inn) where U : struct, T
{
if (typeof(T).IsEnum)
{
EnumValue = inn;
}
}
}
and invoke it like this
var agen = new EnumWrapper<gender>();
gender g=new gender() ;
agen.Assign (g);
EDIT: Assign() is a dummy method. My intention was to show how to use enum as generic constraint.
It is not possible to have generic conversion operators. So, there can't be exact generic equivalent for above code. Besides, one cannot mention enum as generic type constraint, so casting within property implementation is also not possible (or may need some other constraint (possibly interface) to work that may result in boxing/unboxing). In short, IMO, having generic solution with reasonable performance may not be feasible.
I would suggest that you try using code generation (look at T4 templates) for creating your wrapper classes. T4 is pretty simple - refer here for few links: http://www.hanselman.com/blog/T4TextTemplateTransformationToolkitCodeGenerationBestKeptVisualStudioSecret.aspx

Categories

Resources