Generic string to enum extension method with default value [duplicate] - c#

I got an Int16 value, from the database, and need to convert this to an enum type. This is unfortunately done in a layer of the code that knows very little about the objects except for what it can gather through reflection.
As such, it ends up calling Convert.ChangeType which fails with an invalid cast exception.
I found what I consider a smelly workaround, like this:
String name = Enum.GetName(destinationType, value);
Object enumValue = Enum.Parse(destinationType, name, false);
Is there a better way, so that I don't have to move through this String operation?
Here's a short, but complete, program that can be used if anyone need to experiment:
using System;
public class MyClass
{
public enum DummyEnum
{
Value0,
Value1
}
public static void Main()
{
Int16 value = 1;
Type destinationType = typeof(DummyEnum);
String name = Enum.GetName(destinationType, value);
Object enumValue = Enum.Parse(destinationType, name, false);
Console.WriteLine("" + value + " = " + enumValue);
}
}

Enum.ToObject(.... is what you're looking for!
C#
StringComparison enumValue = (StringComparison)Enum.ToObject(typeof(StringComparison), 5);
VB.NET
Dim enumValue As StringComparison = CType([Enum].ToObject(GetType(StringComparison), 5), StringComparison)
If you do a lot of Enum converting try using the following class it will save you alot of code.
public class Enum<EnumType> where EnumType : struct, IConvertible
{
/// <summary>
/// Retrieves an array of the values of the constants in a specified enumeration.
/// </summary>
/// <returns></returns>
/// <remarks></remarks>
public static EnumType[] GetValues()
{
return (EnumType[])Enum.GetValues(typeof(EnumType));
}
/// <summary>
/// Converts the string representation of the name or numeric value of one or more enumerated constants to an equivalent enumerated object.
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
/// <remarks></remarks>
public static EnumType Parse(string name)
{
return (EnumType)Enum.Parse(typeof(EnumType), name);
}
/// <summary>
/// Converts the string representation of the name or numeric value of one or more enumerated constants to an equivalent enumerated object.
/// </summary>
/// <param name="name"></param>
/// <param name="ignoreCase"></param>
/// <returns></returns>
/// <remarks></remarks>
public static EnumType Parse(string name, bool ignoreCase)
{
return (EnumType)Enum.Parse(typeof(EnumType), name, ignoreCase);
}
/// <summary>
/// Converts the specified object with an integer value to an enumeration member.
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
/// <remarks></remarks>
public static EnumType ToObject(object value)
{
return (EnumType)Enum.ToObject(typeof(EnumType), value);
}
}
Now instead of writing (StringComparison)Enum.ToObject(typeof(StringComparison), 5); you can simply write Enum<StringComparison>.ToObject(5);.

Based on the #Peter's answer here is the method for Nullable<int> to Enum conversion:
public static class EnumUtils
{
public static bool TryParse<TEnum>(int? value, out TEnum result)
where TEnum: struct, IConvertible
{
if(!value.HasValue || !Enum.IsDefined(typeof(TEnum), value)){
result = default(TEnum);
return false;
}
result = (TEnum)Enum.ToObject(typeof(TEnum), value);
return true;
}
}
Using EnumUtils.TryParse<YourEnumType>(someNumber, out result) becomes useful for many scenarios. For example, WebApi Controller in Asp.NET does not have default protection against invalid Enum params. Asp.NET will just use default(YourEnumType) value, even if some passes null, -1000, 500000, "garbage string" or totally ignores the parameter. Moreover, ModelState will be valid in all these cases, so one of the solution is to use int? type with custom check
public class MyApiController: Controller
{
[HttpGet]
public IActionResult Get(int? myEnumParam){
MyEnumType myEnumParamParsed;
if(!EnumUtils.TryParse<MyEnumType>(myEnumParam, out myEnumParamParsed)){
return BadRequest($"Error: parameter '{nameof(myEnumParam)}' is not specified or incorrect");
}
return this.Get(washingServiceTypeParsed);
}
private IActionResult Get(MyEnumType myEnumParam){
// here we can guarantee that myEnumParam is valid
}

If you are storing an Enum in a DataTable but don't know which column is an enum and which is a string/int, you can access the value this way:
foreach (DataRow dataRow in myDataTable.Rows)
{
Trace.WriteLine("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
foreach (DataColumn dataCol in myDataTable.Columns)
{
object v = dataRow[dataCol];
Type t = dataCol.DataType;
bool e = false;
if (t.IsEnum) e = true;
Trace.WriteLine((dataCol.ColumnName + ":").PadRight(30) +
(e ? Enum.ToObject(t, v) : v));
}
}

Related

Using System.Reflection to retrieve a list of const string fields

I've created a class of classes (showing one of them) with const string that I want to itarate on.
public static class HTDB_Cols
{
public sealed class Assistant
{
public const string EntryID = "entryID",
CustName = "custName",
SerialNum = "serialNum",
UserName = "userName",
Password = "password",
EndDate = "end_date",
CustID = "custID",
TmpCheck = "tmpCheck",
Isfamily = "isfamily",
Isserver = "isserver";
}
}
public static class DB
{
public static void insert(string TableName)
{
ColumnsCollection = typeof(HTDB_Cols).GetNestedTypes().Where(f => f.DeclaringType.Name.ToLower().Equals(TableName.ToLower()));
}
}
The code above shows my attempt, but even after lots of trial and error I still couldn't get it right.
I want to have a list of all columns as const collection array or list.
var dict = typeof(HTDB_Cols).GetNestedTypes()
.First(t=>String.Compare(t.Name,TableName,true)==0)
.GetFields()
.ToDictionary(f => f.Name, f => f.GetValue(null));
To get a list
var list = typeof(HTDB_Cols).GetNestedTypes()
.First(t => String.Compare(t.Name, TableName, true) == 0)
.GetFields()
.Select(f => f.GetValue(null) as string)
.ToList();
It looks like what you need is an enum:
enum Assistant
{
EntryID,
CustName,
SerialNum,
UserName,
Password,
EndDate,
CustID,
TmpCheck,
Isfamily,
Isserver
};
You can then get all of those names as strings by doing:
string[] allNames = Enum.GetNames(typeof(Assistant));
As long as it's acceptable for you to have the names of the variables be the actual values that you care about, that's a valid option. I note that they're not quite the same in your example, but it's mostly just casing. If you can deal with using the variable names as the values, or changing the variable names to be the values you need, then that's likely to be your best option.
Now, if it really is important for the variable names to be different than the values they represent, or if you need to represent values that are illegal identifiers (for example, one of your values has a space, that's no good, and they couldn't ever start with a digit, or they might just be too long to be a convenient name). If that's the case, then what you really want is an enum that's backed by a string, rather than an integer or other numeric type. That's not strictly possible in C#, but since this has come up before I actually wrote the following class which is my best attempt at creating my own string backed enum. If you really need variable names that differ from the string values they represent, this should work for you.
All of the important stuff is right at the top, most everything after Equals is just syntactic sugar.
public struct StringEnum
{
#region Code that is to be configured
//For each value to be publicly exposed add a new field.
public static readonly StringEnum Alpha = new StringEnum("Alpha Value");
public static readonly StringEnum Beta = new StringEnum("Beta Value");
public static readonly StringEnum Invalid = new StringEnum("Invalid");
public static IEnumerable<StringEnum> AllValues
{
get
{
yield return Alpha;
yield return Beta;
yield return Invalid;
//...
//add a yield return for all instances here.
//TODO refactor to use reflection so it doesn't need to be manually updated.
}
}
#endregion
private string value;
/// <summary>
/// default constructor
/// </summary>
//private Group()
//{
// //You can make this default value whatever you want. null is another option I considered
// //(if this is a class an not a struct), but you
// //shouldn't have this be anything that doesn't exist as one of the options defined at the top of
// //the page.
// value = "Invalid";
//}
/// <summary>
/// primary constructor
/// </summary>
/// <param name="value">The string value that this is a wrapper for</param>
private StringEnum(string value)
{
this.value = value;
}
/// <summary>
/// Compares the StringEnum to another StringEnum, or to a string value.
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public override bool Equals(object obj)
{
if (obj is StringEnum)
{
return this.Equals((StringEnum)obj);
}
string otherString = obj as string;
if (otherString != null)
{
return this.Equals(otherString);
}
throw new ArgumentException("obj is neither a StringEnum nor a String");
}
/// <summary>
/// Strongly typed equals method.
/// </summary>
/// <param name="other">Another StringEnum to compare this object to.</param>
/// <returns>True if the objects are equal.</returns>
public bool Equals(StringEnum other)
{
return value == other.value;
}
/// <summary>
/// Equals method typed to a string.
/// </summary>
/// <param name="other">A string to compare this object to.
/// There must be a Group associated with that string.</param>
/// <returns>True if 'other' represents the same Group as 'this'.</returns>
public bool Equals(string other)
{
return value == other;
}
/// <summary>
/// Overridden equals operator, for convenience.
/// </summary>
/// <param name="first"></param>
/// <param name="second"></param>
/// <returns>True if the objects are equal.</returns>
public static bool operator ==(StringEnum first, StringEnum second)
{
return object.Equals(first, second);
}
public static bool operator !=(StringEnum first, StringEnum second)
{
return !object.Equals(first, second);
}
/// <summary>
/// Properly overrides GetHashCode so that it returns the hash of the wrapped string.
/// </summary>
/// <returns></returns>
public override int GetHashCode()
{
return value.GetHashCode();
}
/// <summary>
/// returns the internal string that this is a wrapper for.
/// </summary>
/// <param name="stringEnum"></param>
/// <returns></returns>
public static implicit operator string(StringEnum stringEnum)
{
return stringEnum.value;
}
/// <summary>
/// Parses a string and returns an instance that corresponds to it.
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static StringEnum Parse(string input)
{
return AllValues.Where(item => item.value == input).FirstOrDefault();
}
/// <summary>
/// Syntatic sugar for the Parse method.
/// </summary>
/// <param name="other"></param>
/// <returns></returns>
public static explicit operator StringEnum(string other)
{
return Parse(other);
}
/// <summary>
/// A string representation of this object.
/// </summary>
/// <returns></returns>
public override string ToString()
{
return value;
}
}

C# IsEqual with ignorable list

I have some classes with lots of simple properties (from a datamodel I have no control over) -- I'd like to be able to find if the new version of an object is the same as an old version, but don't want to do 20 different "IsEqual" methods (I don't really like the "IsEqual" name because it is not an analog to ==). Another wrinkle, in most of the cases I don't want it to do a deep compare, but in some cases I do want that.
I'd like something along the lines of:
//Property could be PropertyInfo if that is necessary
bool IsEqual<T>(T first, T second, List<Property> ignorableProperties=emptyList, bool recurse=false)
{
//the comparison code returning if they are equal ignoring
//the properties in the ignorableProperties list, recursing if recurse == true
//not sure how I'd handle the comparison of sub-objects in the recursive step.
}
public static bool AreEqual<T>(this T first, T second,
bool recurse = false, params string[] propertiesToSkip)
{
if (Equals(first, second)) return true;
if (first == null)
return second == null;
else if (second == null)
return false;
if (propertiesToSkip == null) propertiesToSkip = new string[] { };
var properties = from t in first.GetType().GetProperties()
where t.CanRead
select t;
foreach (var property in properties)
{
if (propertiesToSkip.Contains(property.Name)) continue;
var v1 = property.GetValue(first, null);
var v2 = property.GetValue(second, null);
if (recurse)
if (!AreEqual(v1, v2, true, propertiesToSkip))
return false;
else
continue;
if (!Equals(v1, v2)) return false;
}
return true;
}
Here's something along those lines from our code base. It uses a list of properties to compare, rather than a list of properties to ignore. Then it returns a list of which properties did not match:
public static List<PropertyInfo> CompareObjects<T>(T o1, T o2, List<PropertyInfo> props) where T : class
{
var type = typeof(T);
var mismatched = CompareObjects(type, o1, o2, props);
return mismatched;
}
public static List<PropertyInfo> CompareObjects(Type t, object o1, object o2, List<PropertyInfo> props)
{
List<PropertyInfo> mismatched = null;
foreach (PropertyInfo prop in props)
{
if (prop.GetValue(o1, null) == null && prop.GetValue(o2, null) == null) ;
else if (
prop.GetValue(o1, null) == null || prop.GetValue(o2, null) == null ||
!prop.GetValue(o1, null).Equals(prop.GetValue(o2, null)))
{
if (mismatched == null) mismatched = new List<PropertyInfo>();
mismatched.Add(prop);
}
}
return mismatched;
}
If you wanted an IsEqual method it would be a matter of returning true/false when you find mismatched properties instead.
Hope this helps!
Here's how we achieve this in the Umbraco Framework, with a base class called AbstractEquatableObject which is a modified version of Sharp Architecture's BaseObject http://umbraco.codeplex.com/SourceControl/changeset/view/2b4d693de19c#Source%2fLibraries%2fUmbraco.Framework%2fAbstractEquatableObject.cs
Implementors override GetMembersForEqualityComparison() and the base class caches the PropertyInfo objects once per Type for the application in a ConcurrentDictionary<Type, IEnumerable<PropertyInfo>>.
I've pasted the class here, although it refers to LogHelper elsewhere in the Framework so you can remove that (or just use our Framework lib, there's other useful stuff in there).
If you want a helper for getting a PropertyInfo from an expression, to avoid magic strings all over the place (e.g. replaced with x => x.MyProperty), check out the GetPropertyInfo methods of our ExpressionHelper at http://umbraco.codeplex.com/SourceControl/changeset/view/2b4d693de19c#Source%2fLibraries%2fUmbraco.Framework%2fExpressionHelper.cs
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Umbraco.Framework.Diagnostics;
namespace Umbraco.Framework
{
/// <summary>
/// Objects implementing <see cref="AbstractEquatableObject{T}"/> are provided with common functionality for establishing domain-specific equality
/// and a robust implementation of GetHashCode
/// </summary>
/// <typeparam name="T"></typeparam>
[Serializable]
public abstract class AbstractEquatableObject<T> where T : AbstractEquatableObject<T>
{
/// <summary>
/// Returns the real type in case the <see cref="object.GetType" /> method has been proxied.
/// </summary>
/// <returns></returns>
/// <remarks></remarks>
protected internal virtual Type GetNativeType()
{
// Returns the real type in case the GetType method has been proxied
// See http://groups.google.com/group/sharp-architecture/browse_thread/thread/ddd05f9baede023a for clarification
return GetType();
}
/// <summary>Returns a hash code for this instance.</summary>
/// <returns>A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. </returns>
public override int GetHashCode()
{
unchecked
{
// Based on an algorithm set out at http://sharp-architecture.googlecode.com/svn/trunk/src/SharpArch/SharpArch.Core/DomainModel/BaseObject.cs
var naturalIdMembers = EnsureEqualityComparisonMembersCached();
// It's possible for two objects to return the same hash code based on
// identically valued properties, even if they're of two different types,
// so we include the object's type in the hash calculation
var hashCode = GetType().GetHashCode();
if (!naturalIdMembers.Any()) return base.GetHashCode();
foreach (var value in naturalIdMembers
.Select(x => x.GetValue(this, null))
.Where(x => !ReferenceEquals(x, null)))
{
// Check if the property value is null or default (e.g. Guid.Empty)
// In which case we just want to use the base GetHashCode because we have no other way
// of determining if the instances are different
if (value.Equals(value.GetType().GetDefaultValue()))
hashCode = (hashCode * 41) ^ base.GetHashCode();
else
hashCode = (hashCode * 41) ^ value.GetHashCode();
}
return hashCode;
}
}
/// <summary>Determines whether the specified object is equal to this instance.</summary>
/// <param name="obj">The <see cref="System.Object"/> to compare with this instance.</param>
/// <returns><c>true</c> if the specified <see cref="System.Object"/> is equal to this instance; otherwise, <c>false</c>.</returns>
public override bool Equals(object obj)
{
if (ReferenceEquals(obj, null)) return false;
var incoming = obj as AbstractEquatableObject<T>;
if (ReferenceEquals(incoming, null)) return false;
if (ReferenceEquals(this, incoming)) return true;
// (APN Oct 2011) Disabled the additional check for GetNativeType().Equals(incoming.GetNativeType())
// so that we can compare RelationById with Relation using Equals however this may need reinstating
// and using IComparable instead
return CompareCustomEqualityMembers(incoming);
}
/// <summary>
/// Implements the operator ==.
/// </summary>
/// <param name="left">The left.</param>
/// <param name="right">The right.</param>
/// <returns>The result of the operator.</returns>
/// <remarks></remarks>
public static bool operator ==(AbstractEquatableObject<T> left, AbstractEquatableObject<T> right)
{
// If both are null, or both are same instance, return true.
if (ReferenceEquals(left, right)) return true;
// If one is null, but not both, return false.
if (((object)left == null) || ((object)right == null)) return false;
return left.Equals(right);
}
/// <summary>
/// Implements the operator !=.
/// </summary>
/// <param name="left">The left.</param>
/// <param name="right">The right.</param>
/// <returns>The result of the operator.</returns>
/// <remarks></remarks>
public static bool operator !=(AbstractEquatableObject<T> left, AbstractEquatableObject<T> right)
{
return !(left == right);
}
/// <summary>
/// A static <see cref="ConcurrentDictionary{Type, IEnumerable{PropertyInfo}}"/> cache of natural ids for types which may implement this abstract class.
/// </summary>
protected readonly static ConcurrentDictionary<Type, IEnumerable<PropertyInfo>> EqualityComparisonMemberCache = new ConcurrentDictionary<Type, IEnumerable<PropertyInfo>>();
/// <summary>
/// Gets the natural id members.
/// </summary>
/// <returns></returns>
/// <remarks></remarks>
protected abstract IEnumerable<PropertyInfo> GetMembersForEqualityComparison();
/// <summary>
/// Ensures the natural id members are cached in the static <see cref="EqualityComparisonMemberCache"/>.
/// </summary>
/// <returns></returns>
/// <remarks></remarks>
protected internal virtual IEnumerable<PropertyInfo> EnsureEqualityComparisonMembersCached()
{
return EqualityComparisonMemberCache.GetOrAdd(GetNativeType(), x => GetMembersForEqualityComparison());
}
/// <summary>
/// Establishes if the natural id of this instance matches that of <paramref name="compareWith"/>
/// </summary>
/// <param name="compareWith">The instance with which to compare.</param>
/// <returns></returns>
/// <remarks></remarks>
protected internal virtual bool CompareCustomEqualityMembers(AbstractEquatableObject<T> compareWith)
{
// Standard input checks - if it's the same instance, or incoming is null, etc.
if (ReferenceEquals(this, compareWith)) return true;
if (ReferenceEquals(compareWith, null)) return false;
// Get the natural id spec
var naturalIdMembers = EnsureEqualityComparisonMembersCached();
// If the overriding objct hasn't specified a natural id, just return the base Equals implementation
if (!naturalIdMembers.Any()) return base.Equals(compareWith);
// We have a natural id specified, so compare the members
foreach (var naturalIdMember in naturalIdMembers)
{
try
{
// Get the property values of this instance and the incoming instance
var localValue = naturalIdMember.GetValue(this, null);
var incomingValue = naturalIdMember.GetValue(compareWith, null);
// If the property values refere to the same instance, or both refer to null, continue the loop
if (ReferenceEquals(localValue, incomingValue) || (ReferenceEquals(localValue, null) && ReferenceEquals(incomingValue, null)))
continue;
// If this property value doesn't equal the incoming value, the comparison fails so we can return straight away
if (!localValue.Equals(incomingValue)) return false;
}
catch (Exception ex)
{
// If there was an error accessing one of the properties, log it and return false
LogHelper.TraceIfEnabled<AbstractEquatableObject<T>>("Error comparing {0} to {1}: {2}",
() => GetNativeType().Name,
() => compareWith.GetNativeType().Name,
() => ex.Message);
return false;
}
}
// To get this far means we haven't had any misses, so return true
return true;
}
}
}

Extending enums in c#

in java im used to extending enum values or overriding methods like this :
enum SomeEnum
{
option1("sv")
{
public String toString()
{
return "Some value";
}
},
option2;
private String PassedValue;
public SomeEnum(String somevalue)
{
this.PassedValue = somevalue;
}
public SomeEnum()
{
this.PassedValue = "Default Value";
}
public String getPassedValue()
{
return this.PassedValue;
}
}
is there a way to do something similar in c# or are enums more limited in c#
I wish enums were more powerful in .Net. And I love .Net! You can use attributes to accomplish the same thing. Write the code below once and use it everywhere. This will be a long answer but I think it's a pretty good solution so have patience!
Usage
SomeEnum e = SomeEnum.ValueTwo;
string description = e.GetDescription();
The Enum
Use attributes to describe the enum and it's values.
[DescriptiveEnumEnforcement(DescriptiveEnumEnforcement.EnforcementTypeEnum.ThrowException)]
public enum SomeEnum
{
[Description("Value One")]
ValueOne,
[Description("Value Two")]
ValueTwo,
[Description("Value 3")]
ValueThree
}
DescriptionAttribute
/// <summary>Indicates that an enum value has a description.</summary>
[AttributeUsage(AttributeTargets.Field)]
public class DescriptionAttribute : System.Attribute
{
/// <summary>The description for the enum value.</summary>
public string Description { get; set; }
/// <summary>Constructs a new DescriptionAttribute.</summary>
public DescriptionAttribute() { }
/// <summary>Constructs a new DescriptionAttribute.</summary>
/// <param name="description">The initial value of the Description property.</param>
public DescriptionAttribute(string description)
{
this.Description = description;
}
/// <summary>Returns the Description property.</summary>
/// <returns>The Description property.</returns>
public override string ToString()
{
return this.Description;
}
}
DescriptiveEnumEnforcementAttribute
An attribute to ensure your enum's are properly configured.
/// <summary>Indicates whether or not an enum must have a NameAttribute and a DescriptionAttribute.</summary>
[AttributeUsage(AttributeTargets.Enum)]
public class DescriptiveEnumEnforcementAttribute : System.Attribute
{
/// <summary>Defines the different types of enforcement for DescriptiveEnums.</summary>
public enum EnforcementTypeEnum
{
/// <summary>Indicates that the enum must have a NameAttribute and a DescriptionAttribute.</summary>
ThrowException,
/// <summary>Indicates that the enum does not have a NameAttribute and a DescriptionAttribute, the value will be used instead.</summary>
DefaultToValue
}
/// <summary>The enforcement type for this DescriptiveEnumEnforcementAttribute.</summary>
public EnforcementTypeEnum EnforcementType { get; set; }
/// <summary>Constructs a new DescriptiveEnumEnforcementAttribute.</summary>
public DescriptiveEnumEnforcementAttribute()
{
this.EnforcementType = EnforcementTypeEnum.DefaultToValue;
}
/// <summary>Constructs a new DescriptiveEnumEnforcementAttribute.</summary>
/// <param name="enforcementType">The initial value of the EnforcementType property.</param>
public DescriptiveEnumEnforcementAttribute(EnforcementTypeEnum enforcementType)
{
this.EnforcementType = enforcementType;
}
}
Getting the Description
/// <summary>Provides functionality to enhance enumerations.</summary>
public static partial class EnumUtil
{
/// <summary>Returns the description of the specified enum.</summary>
/// <param name="value">The value of the enum for which to return the description.</param>
/// <returns>A description of the enum, or the enum name if no description exists.</returns>
public static string GetDescription(this Enum value)
{
return GetEnumDescription(value);
}
/// <summary>Returns the description of the specified enum.</summary>
/// <param name="value">The value of the enum for which to return the description.</param>
/// <returns>A description of the enum, or the enum name if no description exists.</returns>
public static string GetDescription<T>(object value)
{
return GetEnumDescription(value);
}
/// <summary>Returns the description of the specified enum.</summary>
/// <param name="value">The value of the enum for which to return the description.</param>
/// <returns>A description of the enum, or the enum name if no description exists.</returns>
public static string GetEnumDescription(object value)
{
if (value == null)
return null;
Type type = value.GetType();
//Make sure the object is an enum.
if (!type.IsEnum)
throw new ApplicationException("Value parameter must be an enum.");
FieldInfo fieldInfo = type.GetField(value.ToString());
object[] descriptionAttributes = fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
//If no DescriptionAttribute exists for this enum value, check the DescriptiveEnumEnforcementAttribute and decide how to proceed.
if (descriptionAttributes == null || descriptionAttributes.Length == 0)
{
object[] enforcementAttributes = fieldInfo.GetCustomAttributes(typeof(DescriptiveEnumEnforcementAttribute), false);
//If a DescriptiveEnumEnforcementAttribute exists, either throw an exception or return the name of the enum instead.
if (enforcementAttributes != null && enforcementAttributes.Length == 1)
{
DescriptiveEnumEnforcementAttribute enforcementAttribute = (DescriptiveEnumEnforcementAttribute)enforcementAttributes[0];
if (enforcementAttribute.EnforcementType == DescriptiveEnumEnforcementAttribute.EnforcementTypeEnum.ThrowException)
throw new ApplicationException("No Description attributes exist in enforced enum of type '" + type.Name + "', value '" + value.ToString() + "'.");
return GetEnumName(value);
}
else //Just return the name of the enum.
return GetEnumName(value);
}
else if (descriptionAttributes.Length > 1)
throw new ApplicationException("Too many Description attributes exist in enum of type '" + type.Name + "', value '" + value.ToString() + "'.");
//Return the value of the DescriptionAttribute.
return descriptionAttributes[0].ToString();
}
}
Enums in C# are for (integer) values only; they cannot have special methods or constructors like in Java.
However, you can define extension methods that work on enums to achieve nearly the same effect:
public enum MyEnum {
Foo = 1,
Bar = 2,
Default = Foo
}
public static class MyEnumExtensions
{
public static Widget ToWidget(this MyEnum enumValue) {
switch (enumValue) {
case MyEnum.Foo:
return new Widget("Foo!");
case MyEnum.Bar:
return new Widget("Bar...");
default:
return null;
}
}
}
Then you could say:
var val = MyEnum.Foo;
var widget = val.ToWidget();
enums in C# are basically just named primitives. They typically are based on int, but can be based on any numeric primitive. So C# does not offer nearly the functionality that Java enums do. The trade off is C# enums are much lighter, whereas Java enums are full fledged objects.
public enum FooBar : int {
Foo = 1,
Bar = 2
}
The above enum is not much different from an int, except we can now use FooBar.Foo instead of the literal 1. You can cast the enum back and forth between ints, and Enum has some helper functions that can help when working with enums. But that's about it for C#, they are much like C or C++ enums.
You can do something similar in C# using Extension methods.
enum Test
{
Value1,
Value2,
Value3
}
static class TextExtensions
{
public static string Value(this Test value)
{
string stringValue = default(String);
switch (value)
{
case Test.Value1:
{
stringValue = "some value 1";
} break;
case Test.Value2:
{
stringValue = "some value 2";
}; break;
case Test.Value3:
{
stringValue = "some value 3";
}; break;
}
return stringValue;
}
}
class Program
{
static void Main(string[] args)
{
Console.Write(Test.Value1.Value());
Console.ReadLine();
}
}

C# string Parsing to variable types

I want to parse a string into a type easily, but I don't want to write wrapper code for each type, I just want to be able to do "1234".Parse() or the like and have it return 1234. This should work for any type that has parsing capabilities.
This trick should work. It uses the type of the variable you're assigning to automagically:
public static class StringExtensions {
public static ParsedString Parse(this string s) {
return new ParsedString(s);
}
}
public class ParsedString {
string str;
public ParsedString(string s) {
str = s;
}
public static implicit operator int(ParsedString s) {
return int.Parse(s.str);
}
public static implicit operator double(ParsedString s) {
return double.Parse(s.str);
}
public static implicit operator short(ParsedString s) {
return short.Parse(s.str);
}
public static implicit operator byte(ParsedString s) {
return byte.Parse(s.str);
}
// ... add other supported types ...
}
Usage:
int p = "1234".Parse();
I would prefer explicitly parsing using framework provided methods rather than relying on these kind of tricks.
My solution works for any type that implements the static method TryParse(string, out T), whether it's a class or a struct. Also, it will work for nullable structs, e.g.
"1234".Parse<int>() == 1234
"asdf".Parse<int>() == 0 // i.e. default(int)
"1234".Parse<int?>() == 1234
"asdf".Parse<int?>() == null
"2001-02-03".Parse<DateTime?>() == new DateTime(2009, 2, 3)
and since System.Net.IPAddress has TryParse,
"127.0.0.1".Parse<IPAddress>().Equals(new IPAddress(new byte[] { 127, 0, 0, 1 }))
I create the code with the System.Linq.Expressions framework, and then cache the created lambda. Since this is done in a generic static class with a specified type, this happens only once per type to parse.
public static class StringExtensions
{
/// <summary>
/// Parse the <paramref name="target"/> as a <typeparamref name="T"/>. If this cannot be achieved, return the default value of <typeparamref name="T"/>.
/// </summary>
/// <typeparam name="T">The type to parse into.</typeparam>
/// <param name="target">The string to parse.</param>
/// <returns>The resultant <typeparamref name="T"/> or the default of <typeparamref name="T"/>.</returns>
/// <example>
/// <code>
/// "1234".Parse&ltint>() == 1234;
/// "a".Parse&ltint>() == 0;
/// "a".Parse&ltint?>() == null;
/// "2010-01-01".Parse<DateTime?>() == new DateTime(2010, 1, 1)
/// "2010-01-01a".Parse<DateTime?>() == null
/// "127.0.0.1".Parse<System.Net.IPAddress>().Equals(new System.Net.IPAddress(new byte[] { 127, 0, 0, 1 }))
/// "".Parse<System.Net.IPAddress>() == null
/// </code>
/// </example>
public static T Parse<T>(this string target)
{
return ParseHelper<T>.Parse(target);
}
/// <summary>
/// Parse the <paramref name="target"/> as a <typeparamref name="T"/>. If this cannot be achieved, return <paramref name="defaultValue"/>
/// </summary>
/// <typeparam name="T">The type to parse into.</typeparam>
/// <param name="target">The string to parse.</param>
/// <param name="defaultValue">The value to return if <paramref name="target"/> could not be parsed.</param>
/// <returns>The resultant <typeparamref name="T"/> or <paramref name="defaultValue"/>.</returns>
/// <example>
/// <code>
/// "1234".Parse&ltint>(-1) == 1234;
/// "a".Parse&ltint>(-1) == -1;
/// "2010-01-01".Parse<DateTime?>(new DateTime(1900, 1, 1)) == new DateTime(2010, 1, 1)
/// "2010-01-01a".Parse<DateTime?>(new DateTime(1900, 1, 1)) == new DateTime(1900, 1, 1)
/// "127.0.0.1".Parse<System.Net.IPAddress>(new System.Net.IPAddress(new byte[] { 0, 0, 0, 0 })).Equals(new System.Net.IPAddress(new byte[] { 127, 0, 0, 1 }))
/// "".Parse<System.Net.IPAddress>(new System.Net.IPAddress(new byte[] { 0, 0, 0, 0 })).Equals(new System.Net.IPAddress(new byte[] { 0, 0, 0, 0 }))
/// </code>
/// </example>
public static T Parse<T>(this string target, T defaultValue)
{
return ParseHelper<T>.Parse(target, defaultValue);
}
private static class ParseHelper<T>
{
private static readonly Func<string, T, T, T> _parser;
static ParseHelper()
{
Type type = typeof(T);
bool isNullable = false;
if (type.GetGenericArguments().Length > 0 && type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
isNullable = true;
type = type.GetGenericArguments()[0];
}
ParameterExpression target = Expression.Parameter(typeof(string), "target");
ParameterExpression defaultValue = Expression.Parameter(typeof(T), "defaultValue");
ParameterExpression result = Expression.Parameter(typeof(T), "result");
if (isNullable)
{
Type helper = typeof(NullableParseHelper<>);
helper = helper.MakeGenericType(typeof(T), type);
MethodInfo parseMethod = helper.GetMethod("Parse");
_parser = Expression.Lambda<Func<string, T, T, T>>(
Expression.Call(parseMethod, target, defaultValue),
target, defaultValue, result).Compile();
}
else
{
MethodInfo tryParseMethod = (from m in typeof(T).GetMethods()
where m.Name == "TryParse"
let ps = m.GetParameters()
where ps.Count() == 2
&& ps[0].ParameterType == typeof(string)
&& ps[1].ParameterType == typeof(T).MakeByRefType()
select m).SingleOrDefault();
if (tryParseMethod == null)
{
throw new InvalidOperationException(string.Format("Cannot find method {0}.TryParse(string, out {0})", type.FullName));
}
_parser = Expression.Lambda<Func<string, T, T, T>>(
Expression.Condition(
Expression.Call(tryParseMethod, target, result),
result,
defaultValue),
target, defaultValue, result).Compile();
}
}
public static T Parse(string target)
{
return _parser.Invoke(target, default(T), default(T));
}
public static T Parse(string target, T defaultValue)
{
return _parser.Invoke(target, defaultValue, default(T));
}
private static class NullableParseHelper<TBase> where TBase : struct
{
private static readonly Func<string, TBase?, TBase, TBase?> _parser;
static NullableParseHelper()
{
MethodInfo tryParseMethod = (from m in typeof(TBase).GetMethods()
where m.Name == "TryParse"
let ps = m.GetParameters()
where ps.Count() == 2
&& ps[0].ParameterType == typeof(string)
&& ps[1].ParameterType == typeof(TBase).MakeByRefType()
select m).SingleOrDefault();
if (tryParseMethod == null)
{
throw new InvalidOperationException(string.Format("Cannot find method {0}.TryParse(string, out {0})", typeof(TBase).FullName));
}
ParameterExpression target = Expression.Parameter(typeof(string), "target");
ParameterExpression defaultValue = Expression.Parameter(typeof(TBase?), "defaultValue");
ParameterExpression result = Expression.Parameter(typeof(TBase), "result");
_parser = Expression.Lambda<Func<string, TBase?, TBase, TBase?>>(
Expression.Condition(
Expression.Call(tryParseMethod, target, result),
Expression.ConvertChecked(result, typeof(TBase?)),
defaultValue),
target, defaultValue, result).Compile();
}
public static TBase? Parse(string target, TBase? defaultValue)
{
return _parser.Invoke(target, defaultValue, default(TBase));
}
}
}
}
pants!
Why can't you use the parsing already available?
int.Parse("1234");
decimal.Parse("1234");
double.Parse("1234");
Or use TryParse if you're not sure it will be able to successfully parse.
Or if you wanted to implement it as an extension method, take a look at this article that will show you how to create a Generic String.Parse method.
Edit: I have no idea how that site went down so quickly after I posted my answer. Here is the class that the article created:
using System;
using System.ComponentModel;
public static class Parser {
public static T Parse<T>(this string value) {
// Get default value for type so if string
// is empty then we can return default value.
T result = default(T);
if (!string.IsNullOrEmpty(value)) {
// we are not going to handle exception here
// if you need SafeParse then you should create
// another method specially for that.
TypeConverter tc = TypeDescriptor.GetConverter(typeof(T));
result = (T)tc.ConvertFrom(value);
}
return result;
}
}
Examples:
// regular parsing
int i = "123".Parse<int>();
int? inull = "123".Parse<int?>();
DateTime d = "01/12/2008".Parse<DateTime>();
DateTime? dn = "01/12/2008".Parse<DateTime?>();
// null values
string sample = null;
int? k = sample.Parse<int?>(); // returns null
int l = sample.Parse<int>(); // returns 0
DateTime dd = sample.Parse<DateTime>(); // returns 01/01/0001
DateTime? ddn = sample.Parse<DateTime?>(); // returns null
I know this question is four years old, but still you could consider using this:
public static T Parse<T>(this string target)
{
Type type = typeof(T);
//In case of a nullable type, use the underlaying type:
var ReturnType = Nullable.GetUnderlyingType(type) ?? type;
try
{
//in case of a nullable type and the input text is null, return the default value (null)
if (ReturnType != type && target == null)
return default(T);
return (T)Convert.ChangeType(target, ReturnType);
}
catch
{
return default(T);
}
}
You can do this with a series of .TryParse() if blocks, but you won't be able to do much with it, since this method will have to return type object. So at the call site, you'll just have to attempt to cast it before doing any arithmetic or anything anyway.
You could write a wrapper function that calls tryParse for each type that you want to support.
There are two problems with that scenario. First you would have to write some code to analyse the string to try to determine what data types it would be possible to parse into, and then some logic to choose one of them. (The string "1" for example would be parsable to byte, sbyte, int, uint, long, ulong, float, double and Decimal. Even worse, the string "4.8.12" would be parsable to several numeric types as well as DateTime in three different ways resulting in totally different values...)
The other problem is that any method capable of doing that would have to return the value boxed in an object, so you would still need wrapper code for each data type just to unbox the value.
Besides, what would you do with a value where you have no control over the type? So, don't try to make this simpler, it only gets a lot more complicated.

Get the Enum<T> value Description

I have my enumHelper class that contains these:
public static IList<T> GetValues()
{
IList<T> list = new List<T>();
foreach (object value in Enum.GetValues(typeof(T)))
{
list.Add((T)value);
}
return list;
}
and
public static string Description(Enum value)
{
Attribute DescAttribute = LMIGHelper.GetAttribute(value, typeof(DescriptionAttribute));
if (DescAttribute == null)
return value.ToString();
else
return ((DescriptionAttribute)DescAttribute).Description;
}
my enum is something like:
public enum OutputType
{
File,
[Description("Data Table")]
DataTable
}
So far so good. All the previous work fine.
Now I want to add a new helper to return BindingList>, so I can link any enum to any combo using
BindingList<KeyValuePair<OutputType, string>> list = Enum<OutputType>.GetBindableList();
cbo.datasource=list;
cbo.DisplayMember="Value";
cbo.ValueMember="Key";
For that I added:
public static BindingList<KeyValuePair<T, string>> GetBindingList()
{
BindingList<KeyValuePair<T, string>> list = new BindingList<KeyValuePair<T, string>>();
foreach (T value in Enum<T>.GetValues())
{
string Desc = Enum<T>.Description(value);
list.Add(new KeyValuePair<T, string>(value, Desc));
}
return list;
}
But "Enum.Description(value)" is not even compiling:
Argument '1': cannot convert from 'T' to 'System.Enum'
How can I do that? Is that even possible?
Thank you.
Take a look at this article. You can do this using the System.ComponentModel.DescriptionAttribute or creating your own attribute:
/// <summary>
/// Provides a description for an enumerated type.
/// </summary>
[AttributeUsage(AttributeTargets.Enum | AttributeTargets.Field,
AllowMultiple = false)]
public sealed class EnumDescriptionAttribute : Attribute
{
private string description;
/// <summary>
/// Gets the description stored in this attribute.
/// </summary>
/// <value>The description stored in the attribute.</value>
public string Description
{
get
{
return this.description;
}
}
/// <summary>
/// Initializes a new instance of the
/// <see cref="EnumDescriptionAttribute"/> class.
/// </summary>
/// <param name="description">The description to store in this attribute.
/// </param>
public EnumDescriptionAttribute(string description)
: base()
{
this.description = description;
}
}
You then need to decorate the enum values with this new attribute:
public enum SimpleEnum
{
[EnumDescription("Today")]
Today,
[EnumDescription("Last 7 days")]
Last7,
[EnumDescription("Last 14 days")]
Last14,
[EnumDescription("Last 30 days")]
Last30,
[EnumDescription("All")]
All
}
All of the "magic" takes place in the following extension methods:
/// <summary>
/// Provides a static utility object of methods and properties to interact
/// with enumerated types.
/// </summary>
public static class EnumHelper
{
/// <summary>
/// Gets the <see cref="DescriptionAttribute" /> of an <see cref="Enum" />
/// type value.
/// </summary>
/// <param name="value">The <see cref="Enum" /> type value.</param>
/// <returns>A string containing the text of the
/// <see cref="DescriptionAttribute"/>.</returns>
public static string GetDescription(this Enum value)
{
if (value == null)
{
throw new ArgumentNullException("value");
}
string description = value.ToString();
FieldInfo fieldInfo = value.GetType().GetField(description);
EnumDescriptionAttribute[] attributes =
(EnumDescriptionAttribute[])
fieldInfo.GetCustomAttributes(typeof(EnumDescriptionAttribute), false);
if (attributes != null && attributes.Length > 0)
{
description = attributes[0].Description;
}
return description;
}
/// <summary>
/// Converts the <see cref="Enum" /> type to an <see cref="IList" />
/// compatible object.
/// </summary>
/// <param name="type">The <see cref="Enum"/> type.</param>
/// <returns>An <see cref="IList"/> containing the enumerated
/// type value and description.</returns>
public static IList ToList(this Type type)
{
if (type == null)
{
throw new ArgumentNullException("type");
}
ArrayList list = new ArrayList();
Array enumValues = Enum.GetValues(type);
foreach (Enum value in enumValues)
{
list.Add(new KeyValuePair<Enum, string>(value, GetDescription(value)));
}
return list;
}
}
Finally, you can then simply bind the combobox:
combo.DataSource = typeof(SimpleEnum).ToList();
You should change:
public static string Description(Enum value)
{
...
}
to
public static string Description(T value)
{
...
}
so it accepts a value of the enumeration. Now here is where it gets tricky: you have a value, but attributes decorate the field which holds the value.
You actually need to reflect over the enumeration's fields and check the value of each against the value you've been given (results should be cached for performance):
foreach(var field in typeof(T).GetFields())
{
T fieldValue;
try
{
fieldValue = (T) field.GetRawConstantValue();
}
catch(InvalidOperationException)
{
// For some reason, one of the fields returned is {Int32 value__},
// which throws an InvalidOperationException if you try and retrieve
// its constant value.
//
// I am unsure how to check for this state before
// attempting GetRawConstantValue().
continue;
}
if(fieldValue == value)
{
var attribute = LMIGHelper.GetAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute;
return attribute == null ? value.ToString() : attribute.Description;
}
}
Edit addressing the follow-up question
The FillComboFromEnum method is missing the type parameter for the enum. Try this:
public static void FillComboFromEnum<T>(ComboBox Cbo, BindingList<KeyValuePair<T, string>> List) where T : struct
Notice I constrained the type to be a struct. It's not a full enumeration constraint, but it's closer than nothing.
Enum doesn't have a Description() method. The best you could do is have your enum implement an interface that has the Description() method. If you do that, then you can have
public static BindingList<KeyValuePair<T extends _interface_, String>> getBindingList()
and then inside of that you can refer to
T foo = ...?
foo.Description(...);

Categories