Generic enum as method parameter - c#

Given a constructor
public MyObject(int id){
ID = id;
}
And two enums:
public enum MyEnum1{
Something = 1,
Anotherthing = 2
}
public enum MyEnum2{
Dodo = 1,
Moustache= 2
}
Is it possible to pass in a generic enum as a parameter of the constructor? I'm looking for a solution along the lines of:
public MyObject(enum someEnum){
ID = (int)someEnum;
}
So you can do:
var newObject = new MyObject(MyEnum1.Something);
var anotherObject = new MyObject(MyEnum2.Dodo);

Another option would be:
public MyObject(Enum someEnum){
ID = Convert.ToInt32(someEnum);
}
This way you can use it like you requested without having to cast to int each time you call your contstructors:
var newObject = new MyObject(MyEnum1.Something);
var anotherObject = new MyObject(MyEnum2.Dodo);

Why do you want to pass the enums, while you could pass integers ?
var newObject = new MyObject((int)MyEnum1.Something);
var anotherObject = new MyObject((int)MyEnum2.Dodo);
and use your first constructor :
public MyObject(int id){
ID = id;
}

Just use a generic constructor:
class MyObject<T> {
public MyObject(T someEnum) where T : struct, IConvertible
{
if (!typeof(T).IsEnum)
throw new ArgumentException("Not an enum");
ID = Convert.ToInt32(someEnum);
}
}
Now you can easily call it like this:
var m = new MyObject<MyEnum>(MyEnum1.Something);
But easier would be to pass the enum as integer to the constructor as mentioned in other answers.
EDIT: As of C# 7.3 you can use an enum-constraint right away:
class MyObject<T> where T: Enum { ... }

Well, if you really need to make this call generic for a wide variety of types, then IMHO you should use:
Type.IsEnum to check if your argument is really an Enum;
Enum.GetUnderlyingType to know what type is your argument is based on (it's not necessarily an Int32);
Now cast your object.
public static Int32 GetAnInt<T>(T arg) where T : struct
{
if ((typeof(T).IsEnum))
{
var underlyingType = typeof(T).GetEnumUnderlyingType();
if (underlyingType == typeof(Int32)
|| underlyingType == typeof(Int16)) //etc.
{
try
{
dynamic value = arg;
var result = (Int32)value; // can throw InvalidCast!
return result;
}
catch
{
throw;
}
}
else
{
throw new InvalidCastException("Underlying type
is certainly not castable to Int32!");
}
}
else
{
throw new InvalidCastException("Not an Enum!");
}
}
That way you achieve the beautiful syntax of: var j = GetAnInt(MyEnum.FirstValue);

Are you using properties enum or parameters.
public enum Enum1{}
public Enum1 enum1 { get;set; }
public MyObject()
{
ID = (int)enum1;
}
Just try it. I hope it is useful.

Related

Convert an enum to List<string>

How do I convert the following Enum to a List of strings?
[Flags]
public enum DataSourceTypes
{
None = 0,
Grid = 1,
ExcelFile = 2,
ODBC = 4
};
I couldn't find this exact question, this Enum to List is the closest but I specifically want List<string>?
Use Enum's static method, GetNames. It returns a string[], like so:
Enum.GetNames(typeof(DataSourceTypes))
If you want to create a method that does only this for only one type of enum, and also converts that array to a List, you can write something like this:
public List<string> GetDataSourceTypes()
{
return Enum.GetNames(typeof(DataSourceTypes)).ToList();
}
You will need Using System.Linq; at the top of your class to use .ToList()
I want to add another solution:
In my case, I need to use a Enum group in a drop down button list items. So they might have space, i.e. more user friendly descriptions needed:
public enum CancelReasonsEnum
{
[Description("In rush")]
InRush,
[Description("Need more coffee")]
NeedMoreCoffee,
[Description("Call me back in 5 minutes!")]
In5Minutes
}
In a helper class (HelperMethods) I created the following method:
public static List<string> GetListOfDescription<T>() where T : struct
{
Type t = typeof(T);
return !t.IsEnum ? null : Enum.GetValues(t).Cast<Enum>().Select(x => x.GetDescription()).ToList();
}
When you call this helper you will get the list of item descriptions.
List<string> items = HelperMethods.GetListOfDescription<CancelReasonEnum>();
ADDITION:
In any case, if you want to implement this method you need :GetDescription extension for enum. This is what I use.
public static string GetDescription(this Enum value)
{
Type type = value.GetType();
string name = Enum.GetName(type, value);
if (name != null)
{
FieldInfo field = type.GetField(name);
if (field != null)
{
DescriptionAttribute attr =Attribute.GetCustomAttribute(field,typeof(DescriptionAttribute)) as DescriptionAttribute;
if (attr != null)
{
return attr.Description;
}
}
}
return null;
/* how to use
MyEnum x = MyEnum.NeedMoreCoffee;
string description = x.GetDescription();
*/
}
In my case, I need to convert it as SelectItem for Checkbox and Radio Button
public class Enum<T> where T : struct, IConvertible
{
public static List<SelectItem> ToSelectItems
{
get
{
if (!typeof(T).IsEnum)
throw new ArgumentException("T must be an enumerated type");
var values = Enum.GetNames(typeof(T));
return values.Select((t, i) => new SelectItem() {Id = i, Name = t}).ToList();
}
}
}

Generic method and passing any enum as parameter

All,
I'm trying to sort out my last bits in a Enum-framework.
My goal: I want to send any enum type and convert it to a List and bind it to a drop down list. i will use an ObjectDataSource as DataSource for the given drop down list. I want to create a composite control that only takes one parameter; enum type. The composite control will sort out databinding and all other bits and bops.
Now, the only problem I have is to convert the generic method to be compatible with the ObjectDataSource.
Here is the code for my current method that i need to use on my ObjectDataSource. So, this method is working fine and returns a list of items for the Enum type WeekDays. However, I need the same functionality, but I need to replace WeekDays with any type of enum.
Code:
public class DropDownData
{
public EnumDataItemList GetList()
{
EnumDataItemList items = new EnumDataItemList();
foreach (int value in Enum.GetValues(WeekDays))
{
EnumDataItem item = new EnumDataItem();
WeekDays d = (WeekDays)value;
//Set display text
if (!string.IsNullOrEmpty(DataHandlers.GetAttributeValue<DisplayTextAttribute, string>(d)))
{
//Translation logic goes here
item.Text = DataHandlers.GetAttributeValue<DisplayTextAttribute, string>(d);
}
else
{
//Translation logic goes here
item.Text = Enum.GetName(typeof(WeekDays), value);
}
item.Value = value; //Actual value
item.ToolTip = DataHandlers.GetAttributeValue<ToolTipAttribute, string>(d);
item.Description = DataHandlers.GetAttributeValue<Lia.Library.Enums.CustomAttributes.DescriptionAttribute, string>(d);
item.HelpText = DataHandlers.GetAttributeValue<HelpTextAttribute, string>(d);
item.ExcludeOnBinding = DataHandlers.GetAttributeValue<ExcludeOnBinding, bool>(d);
if (!item.ExcludeOnBinding)
{
items.Add(item);
}
}
return items;
}
}
public class EnumDataItemList : List<EnumDataItem>
{
}
As far as I know, I can't use a generic method with ObjectDataSOurce, but Generic Class is fine. I just can't get it to work with a generic class and all help is much appreciated. When all is working, I'll be happy to share the complete solution.
I'm using Framework 2.0.
This should help you. (Will throw Exception if T is not an enum type.)
public static EnumDataItemList GetList<T>() where T : struct
{
EnumDataItemList items = new EnumDataItemList();
foreach (int e in Enum.GetValues(typeof(T)))
{
EnumDataItem item = new EnumDataItem();
item.Text = Enum.GetName(typeof(T), e);
item.Value = e;
}
//Rest of code goes here
}
Usage:
EnumDataItemList days = GetList<WeekDays>();
if you don't want to use a generic method, you can change it to:
public static EnumDataItemList GetList(Type t)
{
EnumDataItemList items = new EnumDataItemList();
foreach (int e in Enum.GetValues(t))
{
EnumDataItem item = new EnumDataItem();
item.Text = Enum.GetName(t, e);
item.Value = e;
}
//Rest of code goes here
}
Alternative to Magnus', but the idea is pretty much exactly the same (just didn't want to throw it out after being beat to it ;-) ) - just iterates over the enum value rather than int. Same usage:
public static class DropDownData
{
// struct, IComparable, IFormattable, IConvertible is as close as we'll
// get to an Enum constraint. We don't actually use the constraint for
// anything except rudimentary compile-time type checking, though, so
// you may leave them out.
public static EnumDataItemList GetList<T>()
where T : struct, IComparable, IFormattable, IConvertible
{
// Just to make the intent explicit. Enum.GetValues will do the
// type check, if this is left out:
if (!typeof(T).IsEnum)
{
throw new ArgumentException("Type must be an enumeration");
}
EnumDataItemList items = new EnumDataItemList();
foreach (Enum e in Enum.GetValues(typeof(T)))
{
EnumDataItem items = new EnumDataItem();
// Note: This assumes the enum's underlying type is
// assignable to Int32 (for example, not a long):
int value = Convert.ToInt32(e);
// The same attribute retrieval code as in the
// WeekDays example, including:
item.Text = e.ToString(); // e is Enum here, no need for GetName
}
}
}
I seem to have gone at this problem a little differently and came up with something fairly terse that appears to work for me. I cannot claim this as original work since I don't remember if I found it and copied it, or if I put it together from bits and pieces I found, with some original work of my own. I put an extension method on enums that gives me a ToDisplayText function for getting my custom enum attribute of the same name.
this.ddlBlah.DataSource =
Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>()
.ToDictionary(x => x, x => x.ToDisplayText());
this.ddlBlahs.DataValueField = "key";
this.ddlBlah.DataTextField = "value";
this.ddlBlah.DataBind();
public static string ToDisplayText(this Enum Value)
{
try
{
Type type = Value.GetType();
MemberInfo[] memInfo = type.GetMember(Value.ToString());
if (memInfo != null && memInfo.Length > 0)
{
object[] attrs = memInfo[0].GetCustomAttributes(
typeof(DisplayText),
false);
if (attrs != null && attrs.Length > 0)
return ((DisplayText)attrs[0]).DisplayedText;
}
}
catch (Exception ex)
{
throw new Exception("Your favorite error handling here");
}
return Value.ToString();
// End of ToDisplayText()
}
[System.AttributeUsage(System.AttributeTargets.Field)]
public class DisplayText : System.Attribute
{
public string DisplayedText;
public DisplayText(string displayText)
{
DisplayedText = displayText;
}
// End of DisplayText class definition
}

C#: how to define an extension method as "with" in F#?

F# has a convenient feature "with", example:
type Product = { Name:string; Price:int };;
let p = { Name="Test"; Price=42; };;
let p2 = { p with Name="Test2" };;
F# created keyword "with" as the record types are by default immutable.
Now, is it possible to define a similar extension in C#?
seems it's a bit tricky, as in C# i'm not sure how to convert a string
Name="Test2"
to a delegate or expression?
public static T With<T, U>(this T obj, Expression<Func<T, U>> property, U value)
where T : ICloneable {
if (obj == null)
throw new ArgumentNullException("obj");
if (property == null)
throw new ArgumentNullException("property");
var memExpr = property.Body as MemberExpression;
if (memExpr == null || !(memExpr.Member is PropertyInfo))
throw new ArgumentException("Must refer to a property", "property");
var copy = (T)obj.Clone();
var propInfo = (PropertyInfo)memExpr.Member;
propInfo.SetValue(copy, value, null);
return copy;
}
public class Foo : ICloneable {
public int Id { get; set; }
public string Bar { get; set; }
object ICloneable.Clone() {
return new Foo { Id = this.Id, Bar = this.Bar };
}
}
public static void Test() {
var foo = new Foo { Id = 1, Bar = "blah" };
var newFoo = foo.With(x => x.Bar, "boo-ya");
Console.WriteLine(newFoo.Bar); //boo-ya
}
Or, using a copy constructor:
public class Foo {
public Foo(Foo other) {
this.Id = other.Id;
this.Bar = other.Bar;
}
public Foo() { }
public int Id { get; set; }
public string Bar { get; set; }
}
public static void Test() {
var foo = new Foo { Id = 1, Bar = "blah" };
var newFoo = new Foo(foo) { Bar = "boo-ya" };
Console.WriteLine(newFoo.Bar);
}
And a slight variation on George's excellent suggestion, that allows for multiple assignments:
public static T With<T>(this T obj, params Action<T>[] assignments)
where T : ICloneable {
if (obj == null)
throw new ArgumentNullException("obj");
if (assignments == null)
throw new ArgumentNullException("assignments");
var copy = (T)obj.Clone();
foreach (var a in assignments) {
a(copy);
}
return copy;
}
public static void Test() {
var foo = new Foo { Id = 1, Bar = "blah" };
var newFoo = foo.With(x => x.Id = 2, x => x.Bar = "boo-ya");
Console.WriteLine(newFoo.Bar);
}
I would probably use the second one since (1) any general purpose solution is going to be unnecessarily slow and convoluted; (2) it has the closest syntax to what you want (and the syntax does what you expect); (3) F# copy-and-update expressions are implemented similarly.
Maybe something like this:
void Main()
{
var NewProduct = ExistingProduct.With(P => P.Name = "Test2");
}
// Define other methods and classes here
public static class Extensions
{
public T With<T>(this T Instance, Action<T> Act) where T : ICloneable
{
var Result = Instance.Clone();
Act(Result);
return Result;
}
}
As an alternative to lambda function, you can use parameters with default values. The only minor issue is that you have to pick some default value that means do not change this parameter (for reference types), but null should be a safe choice:
class Product {
public string Name { get; private set; }
public int Price { get; private set; }
public Product(string name, int price) {
Name = name; Price = price;
}
// Creates a new product using the current values and changing
// the values of the specified arguments to a new value
public Product With(string name = null, int? price = null) {
return new Product(name ?? Name, price ?? Price);
}
}
// Then you can write:
var prod2 = prod1.With(name = "New product");
You have to define the method yourself, but that's always the case (unless you're going to use reflection, which less efficient). I think the syntax is reasonably nice too. If you want to make it as nice as in F#, then you'll have to use F# :-)
There is no native ability to do this in C# short of an extension method, but at what cost? a and b are reference types and any suggestion that b is based ("with") on a causes immediate confusion as to how many objects we are working with. Is there only one? Is b a copy of a ? Does b point to a ?
C# is not F#.
Please see a previous SO question of mine as answered by Eric Lippert:
"Amongst my rules of thumb for writing clear code is: put all side effects in statements; non-statement expressions should have no side effects."
More fluent C# / .NET

Extension method on enumeration, not instance of enumeration

I have an enumeration for my Things like so:
public enum Things
{
OneThing,
AnotherThing
}
I would like to write an extension method for this enumeration (similar to Prise's answer here) but while that method works on an instance of the enumeration, ala
Things thing; var list = thing.ToSelectList();
I would like it to work on the actual enumeration instead:
var list = Things.ToSelectList();
I could just do
var list = default(Things).ToSelectList();
But I don't like the look of that :)
I have gotten closer with the following extension method:
public static SelectList ToSelectList(this Type type)
{
if (type.IsEnum)
{
var values = from Enum e in Enum.GetValues(type)
select new { ID = e, Name = e.ToString() };
return new SelectList(values, "Id", "Name");
}
else
{
return null;
}
}
Used like so:
var list = typeof(Things).ToSelectList();
Can we do any better than that?
Extension methods only work on instances, so it can't be done, but with some well-chosen class/method names and generics, you can produce a result that looks just as good:
public class SelectList
{
// Normal SelectList properties/methods go here
public static SelectList Of<T>()
{
Type t = typeof(T);
if (t.IsEnum)
{
var values = from Enum e in Enum.GetValues(type)
select new { ID = e, Name = e.ToString() };
return new SelectList(values, "Id", "Name");
}
return null;
}
}
Then you can get your select list like this:
var list = SelectList.Of<Things>();
IMO this reads a lot better than Things.ToSelectList().
No.
The best you can do is put it on a static class, like this:
public static class ThingsUtils {
public static SelectList ToSelectList() { ... }
}
Aaronaught's answer is really great, based on that I made the following implementation:
public class SelectList
{
public static IEnumerable<Enum> Of<T>() where T : struct, IConvertible
{
Type t = typeof(T);
if (t.IsEnum)
{
return Enum.GetValues(t).Cast<Enum>();
}
throw new ArgumentException("<T> must be an enumerated type.");
}
}
In my opinion it's a little bit safer, as you can - almost - call it only with Enums, and of course instead of the throw you can simply return null if you want an exception-free version.
I use 'Type' instead of 'Enum' to add extension. Then I can get any type of list back from the method. Here it returns string values:
public static string[] AllDescription(this Type enumType)
{
if (!enumType.IsEnum) return null;
var list = new List<string>();
var values = Enum.GetValues(enumType);
foreach (var item in values)
{
// add any combination of information to list here:
list.Add(string.Format("{0}", item));
//this one gets the values from the [Description] Attribute that I usually use to fill drop downs
//list.Add(((Enum) item).GetDescription());
}
return list.ToArray();
}
Later I could use this syntax to get what I want:
var listOfThings = typeof (Things).AllDescription();
#Aaronaught has a very good answer. To extend his answer, you can also even make it more generic. I have this in a global library...
public static IQueryable GetAllEnumValues<T>()
{
IQueryable retVal = null;
Type targetType = typeof(T);
if(targetType.IsEnum)
{
retVal = Enum.GetValues(targetType).AsQueryable();
}
return retVal;
}
Now you have de-coupled this functionality from the SelectList class. So you can call this in your SelectList methods, or anywhere else for that matter.
public class SelectList
{
public static SelectList Of<T>
{
IQueryable enumValues = GetAllEnumValues<T>();
var values =
from Enum e in enumValues
select new { ID = e, Name = e.ToString() };
return new SelectList(values, "Id", "Name");
}
}
In my opinion, this is the cleanest way. Why?
It works for any System.Enum
The extension method itself is cleaner.
To call it you just add new and that's a small trade off (because it has to have an instance in order to work.
You aren't passing null around and it literally won't compile if you try to use it with another type.
Usage:
(new Things()).ToSelectList()
Extension Method:
[Extension()]
public SelectList ToSelectList(System.Enum source)
{
var values = from Enum e in Enum.GetValues(source.GetType)
select new { ID = e, Name = e.ToString() };
return new SelectList(values, "Id", "Name");
}
The closest you can come, I think, is to dummy things up a bit to work like an enum without being one. Here's what I've come up with--it seems like a lot of work just to plop a static method on an enumeration, although I do understand the programming appeal of it:
public class PseudoEnum
{
public const int FirstValue = 1;
private static PseudoEnum FirstValueObject = new PseudoEnum(1);
public const int SecondValue = 2;
private static PseudoEnum SecondValueObject = new PseudoEnum(2);
private int intValue;
// This prevents instantation; note that we cannot mark the class static
private PseudoEnum() {}
private PseudoEnum(int _intValue)
{
intValue = _intValue;
}
public static implicit operator int(PseudoEnum i)
{
return i.intValue;
}
public static implicit operator PseudoEnum(int i)
{
switch (i)
{
case FirstValue :
return FirstValueObject;
case SecondValue :
return SecondValueObject;
default:
throw new InvalidCastException();
}
}
public static void DoSomething(PseudoEnum pe)
{
switch (pe)
{
case PseudoEnum.FirstValue:
break;
case PseudoEnum.SecondValue:
break;
}
}
}

new() with reflection on FieldType

I have some code that looks like
else if (oField.FieldType.IsClass)
{
//var t = oField.FieldType.new()
someObj.fill_data(t);
oField.SetValue(o, t);
}
I dont know how to allocate var t. How might i do this? There no way for me to know what the type could be so writing FieldType.IsAssignableFrom(KnownType) can not be a workaround.
Try Activator.CreateInstance:
object t = Activator.CreateInstance(oField.FieldType);
This assumes that type FieldType has a default constructor.
Here is some example code:
class TypeTest
{
int m_parameter;
public TypeTest()
{
}
public TypeTest(int parameter)
{
m_parameter = parameter;
}
public int Param { get { return m_parameter; } }
}
//method1 - Using generic CreateInstance
TypeTest defConstructor = Activator.CreateInstance <TypeTest>();
//method2 - Using GetConstructor
ConstructorInfo c = typeof(TypeTest).GetConstructor(new Type[] { typeof(int)});
TypeTest getConstructor = (TypeTest)c.Invoke(new object[] { 6 });
//method3 - Using non-generic CreateInstance
TypeTest nonDefaultConstructor = (TypeTest)Activator.CreateInstance(typeof(TypeTest), 6);
Perhaps you should look into the Type.GetConstructor(...).Invoke(...) of the returned Type.

Categories

Resources