Is there a cleaner, more clever way to do this?
I'm hitting a DB to get data to fill an object and am converting a database string value back into its enum (we can assume that all values in the database are indeed values in the matching enum)
The line in question is the line below that sets EventLog.ActionType...the reason I began to question my method is because after the equals sign, VS2010 keeps trying to override what I'm typing by putting this: "= EventActionType("
using (..<snip>..)
{
while (reader.Read())
{
// <snip>
eventLog.ActionType = (EventActionType)Enum.Parse(typeof(EventActionType), reader[3].ToString());
...etc...
As far as I know, this is the best way to do it. I've set up a utility class to wrap this functionality with methods that make this look cleaner, though.
/// <summary>
/// Convenience method to parse a string as an enum type
/// </summary>
public static T ParseEnum<T>(this string enumValue)
where T : struct, IConvertible
{
return EnumUtil<T>.Parse(enumValue);
}
/// <summary>
/// Utility methods for enum values. This static type will fail to initialize
/// (throwing a <see cref="TypeInitializationException"/>) if
/// you try to provide a value that is not an enum.
/// </summary>
/// <typeparam name="T">An enum type. </typeparam>
public static class EnumUtil<T>
where T : struct, IConvertible // Try to get as much of a static check as we can.
{
// The .NET framework doesn't provide a compile-checked
// way to ensure that a type is an enum, so we have to check when the type
// is statically invoked.
static EnumUtil()
{
// Throw Exception on static initialization if the given type isn't an enum.
Require.That(typeof (T).IsEnum, () => typeof(T).FullName + " is not an enum type.");
}
public static T Parse(string enumValue)
{
var parsedValue = (T)System.Enum.Parse(typeof (T), enumValue);
//Require that the parsed value is defined
Require.That(parsedValue.IsDefined(),
() => new ArgumentException(string.Format("{0} is not a defined value for enum type {1}",
enumValue, typeof(T).FullName)));
return parsedValue;
}
public static bool IsDefined(T enumValue)
{
return System.Enum.IsDefined(typeof (T), enumValue);
}
}
With these utility methods, you can just say:
eventLog.ActionType = reader[3].ToString().ParseEnum<EventActionType>();
You can use extension methods to give some syntactic sugar to your code. You can even made this extension methods generics.
This is the kind of code I'm talking about: http://geekswithblogs.net/sdorman/archive/2007/09/25/Generic-Enum-Parsing-with-Extension-Methods.aspx
public static T EnumParse<T>(this string value)
{
return EnumHelper.EnumParse<T>(value, false);
}
public static T EnumParse<T>(this string value, bool ignoreCase)
{
if (value == null)
{
throw new ArgumentNullException("value");
}
value = value.Trim();
if (value.Length == 0)
{
throw new ArgumentException("Must specify valid information for parsing in the string.", "value");
}
Type t = typeof(T);
if (!t.IsEnum)
{
throw new ArgumentException("Type provided must be an Enum.", "T");
}
T enumType = (T)Enum.Parse(t, value, ignoreCase);
return enumType;
}
SimpleEnum enumVal = Enum.Parse<SimpleEnum>(stringValue);
Could use an extension method like so:
public static EventActionType ToEventActionType(this Blah #this) {
return (EventActionType)Enum.Parse(typeof(EventActionType), #this.ToString());
}
And use it like:
eventLog.ActionType = reader[3].ToEventActionType();
Where Blah above is the type of reader[3].
You could get any enum value back, not just EventActionType as in your case with the followin method.
public static T GetEnumFromName<T>(this object #enum)
{
return (T)Enum.Parse(typeof(T), #enum.ToString());
}
You can call it then,
eventLog.ActionType = reader[3].GetEnumFromName<EventActionType>()
This is a more generic approach.
#StriplingWarrior's answer didn't work at first try, so I made some modifications:
Helpers/EnumParser.cs
namespace MyProject.Helpers
{
/// <summary>
/// Utility methods for enum values. This static type will fail to initialize
/// (throwing a <see cref="TypeInitializationException"/>) if
/// you try to provide a value that is not an enum.
/// </summary>
/// <typeparam name="T">An enum type. </typeparam>
public static class EnumParser<T>
where T : struct, IConvertible // Try to get as much of a static check as we can.
{
// The .NET framework doesn't provide a compile-checked
// way to ensure that a type is an enum, so we have to check when the type
// is statically invoked.
static EnumParser()
{
// Throw Exception on static initialization if the given type isn't an enum.
if (!typeof (T).IsEnum)
throw new Exception(typeof(T).FullName + " is not an enum type.");
}
public static T Parse(string enumValue)
{
var parsedValue = (T)Enum.Parse(typeof (T), enumValue);
//Require that the parsed value is defined
if (!IsDefined(parsedValue))
throw new ArgumentException(string.Format("{0} is not a defined value for enum type {1}",
enumValue, typeof(T).FullName));
return parsedValue;
}
public static bool IsDefined(T enumValue)
{
return Enum.IsDefined(typeof (T), enumValue);
}
}
}
Extensions/ParseEnumExtension.cs
namespace MyProject.Extensions
{
public static class ParseEnumExtension
{
/// <summary>
/// Convenience method to parse a string as an enum type
/// </summary>
public static T ParseEnum<T>(this string enumValue)
where T : struct, IConvertible
{
return EnumParser<T>.Parse(enumValue);
}
}
}
Related
I want to create a class to call stored procedures in my SQL Server. I'm using C# with .NET Core 3.1. All stored procedures return the same results but in some cases I have to do more activities and then every function has its own return type base on a base class, in the code below called BaseResponse.
public class BaseResponse
{
public int ErrorCode { get; set; }
public string Message { get; set; }
}
public class InvoiceResponse : BaseResponse
{
public bool IsPaid { get; set; }
}
Then, I have my BaseCall that it is responsible to call a stored procedure and return the BaseResponse.
public async Task<BaseResponse> BaseCall(string procedureName, string[] params)
{
BaseResponse rtn = new BaseResponse();
// call SQL Server stored procedure
return rtn;
}
In another class I want to cast the BaseResponse with the derive class. For that, I thought I can cast the BaseResponse with the derive class but I was wrong.
public async Task<InvoiceResponse> GetInvoice(int id)
{
InvoiceResponse rtn = new InvoiceResponse();
BaseResponse response = BaseCall("myprocedure", null);
rtn = (InvoiceResponse)response;
// do something else
return rtn;
}
I saw other two posts (Convert base class to derived class and this one) and I understood I can't cast in the way I wanted. Then I was my extension from that
/// <summary>
/// Class BaseClassConvert.
/// </summary>
public static class BaseClassConvert
{
/// <summary>
/// Maps to new object.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="sourceobject">The sourceobject.</param>
/// <returns>T.</returns>
/// <remarks>
/// The target object is created on the fly and the target type
/// must have a parameterless constructor (either compiler-generated or explicit)
/// </remarks>
public static T MapToNewObject<T>(this object sourceobject) where T : new()
{
// create an instance of the target class
T targetobject = (T)Activator.CreateInstance(typeof(T));
// map the source properties to the target object
MapToExistingObject(sourceobject, targetobject);
return targetobject;
}
/// <summary>
/// Maps to existing object.
/// </summary>
/// <param name="sourceobject">The sourceobject.</param>
/// <param name="targetobject">The targetobject.</param>
/// <remarks>The target object is created beforehand and passed in</remarks>
public static void MapToExistingObject(this object sourceobject, object targetobject)
{
// get the list of properties available in source class
var sourceproperties = sourceobject.GetType().GetProperties().ToList();
// loop through source object properties
sourceproperties.ForEach(sourceproperty =>
{
var targetProp = targetobject.GetType().GetProperty(sourceproperty.Name);
// check whether that property is present in target class and is writeable
if (targetProp != null && targetProp.CanWrite)
{
// if present get the value and map it
var value = sourceobject.GetType().GetProperty(sourceproperty.Name).GetValue(sourceobject, null);
targetobject.GetType().GetProperty(sourceproperty.Name).SetValue(targetobject, value, null);
}
});
}
}
This code is working and I can use it like:
public async Task<InvoiceResponse> GetInvoice(int id)
{
InvoiceResponse rtn = new InvoiceResponse();
BaseResponse response = BaseCall("myprocedure", null);
response.MapToExistingObject(rtn);
// do something else
return rtn;
}
My questions are:
is there a more efficient way to cast the base class with a derive class in .NET Core?
is this the best practice for casting?
any other guide lines?
this procedure is using Reflection. In performance point of view, is it the right and cheapest way to implement this cast?
You can't cast (without getting error) expression returning/containing base class instance to any inheritor type if this instance not actually inherits it (and to check this there are type-testing operators in C#). Casting as the docs state is an attempt by compiler to perform an explicit conversion in runtime. Also as you mentioned you can't implement custom explicit conversion from or to base class.
What are you looking for (and trying to do) is called mapping and there are a lot of libraries for that, including but not limited to Automapper, Mapster or ExpressMapper for example.
I want to create a class that can keep a number between to values. Here for I have created my first two generic classes.
The first called LimitRang and keep two limit rang variables; one for the lower rang and for the top rang. The second called NumberLimitRang and keep the number and the first class LimitRang.
When I try to create the variable mvarRang, how is a LimitRang var, in the constructor of NumberLimitRang I receive the error : 'Cannot implicitly convert type 'VariableTypes.Supplement.LimitRang' to 'T'.
My code for LimitRang:
namespace VariableTypes.Supplement
{
/// <summary>
/// Manage the boundaries for a number.
/// </summary>
/// <typeparam name="T">The numberic type for the limit parameters</typeparam>
public class LimitRang<T> where T : IComparable
{
private T mvarLowestLimitNumber;
private T mvarHighestLimitNumber;
/// <summary>
/// The default constructor (between 0 and 100)
/// </summary>
public LimitRang()
{
if (Functions.IsNumericType(typeof(T)))
{
try
{
mvarLowestLimitNumber = (T)Convert.ChangeType(0, typeof(T));
mvarHighestLimitNumber = (T)Convert.ChangeType(100, typeof(T));
}
catch
{
mvarLowestLimitNumber = default(T);
mvarHighestLimitNumber = default(T);
}
}
}
}
}
My code for NumberLimitRang:
namespace VariableTypes
{
/// <summary>
/// Can contain a number that need to be between or equal to two limit numbers
/// </summary>
public class NumberLimitRang<T> where T : IComparable
{
private Supplement.LimitRang<T> mvarRang;
private T mvarNumber;
/// <summary>
/// The default constructor (between 0 and 100/Number = 0)
/// </summary>
public NumberLimitRang(T mvarRang)
{
mvarRang = new Supplement.LimitRang<T>();
mvarNumber = (T)Convert.ChangeType(0, typeof(T));
}
}
}
Even when I replace the two T's into int, I still receive the error:
- private Supplement.LimitRang<int> mvarRang;
- mvarRang = new Supplement.LimitRang<int>();
Can you tell me what I do wrong?
Thx a lot
Problem is here:
public NumberLimitRang(T mvarRang)
{
mvarRang = new LimitRang<T>();
mvarNumber = (T)Convert.ChangeType(0, typeof(T));
}
You pass mvarRang as an argument and you have field with name mvarRang. But in method NumberLimitRang compiler uses mvarRang as argument, wich is type of T and tryes to replace it's value with new LimitRang<T>();.
So, first of all, rename field or argument. For example:
public class NumberLimitRang<T> where T : IComparable
{
private LimitRang<T> _mvarRang;
private T _mvarNumber;
/// <summary>
/// The default constructor (between 0 and 100/Number = 0)
/// </summary>
public NumberLimitRang(T mvarRang)
{
_mvarRang = new LimitRang<T>();
_mvarNumber = (T)Convert.ChangeType(0, typeof(T));
}
}
It's good practice to name fields with _ in the beginning.
But now, your argument mvarRang is unused. Revise your logic in code.
public NumberLimitRang(T mvarRang)
{
mvarRang = new Supplement.LimitRang<T>();
mvarNumber = (T)Convert.ChangeType(0, typeof(T));
}
The constructor takes a variable mvarRang of type T. This declaration hides the instance member mvarRang of the type LimitRang<T>.
Either change the parameter name, or refer to the instance member explicitly using this:
public NumberLimitRang(T mvarRang)
{
this.mvarRang = new Supplement.LimitRang<T>();
mvarNumber = (T)Convert.ChangeType(0, typeof(T));
}
I would like to return the string value of an enum stored as an integer in a database using a LINQ query.
What I have tried:
return (from a in context.Tasks
select new TaskSearch
{
TaskID = a.TaskID,
TaskTypeName = Enum.GetName(typeof(TaskTypeEnum), a.TaskType)
}).ToList();
I'm using asp.net mvc.
Exception:
An exception of type 'System.NotSupportedException' occurred in EntityFramework.SqlServer.dll but was not handled in user code
Additional information: LINQ to Entities does not recognize the method 'System.String GetName(System.Type, System.Object)' method, and this method cannot be translated into a store expression.
You need to materialize your query (a query must be able to be converted to a sql statement, but Enum.GetName() cannot be converted to sql)
Try
((from a in context.Tasks select a).AsEnumerable().Select(t => new TaskSearch
{
TaskID = t.TaskID,
TaskTypeName = Enum.GetName(typeof(TaskTypeEnum), t.TaskType)
}).ToList());
I define a set of Enum extensions like this which I have found useful. Unfortunately the Type constraints cannot be refined beyond struct, so you must externally ensure that the methods are only called on Enums.:
/// <summary>Type-safe extension methods for parsing Enums.</summary>
public static partial class EnumExtensions{
#region Enum Parsing utilities
/// <summary>Typesafe wrapper for <c>Enum.GetValues(typeof(TEnum).</c></summary>
public static ReadOnlyCollection<TEnum> EnumGetValues<TEnum>() {
return new ReadOnlyCollection<TEnum>((TEnum[])(Enum.GetValues(typeof(TEnum))));
}
/// <summary>TODO</summary>
[SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
public static ReadOnlyCollection<string> EnumGetNames<TEnum>() where TEnum : struct {
return new ReadOnlyCollection<string>((string[])(Enum.GetNames(typeof(TEnum))));
}
/// <summary>Typesafe wrapper for <c>Enum.ParseEnum()</c> that automatically checks
/// constants for membership in the <c>enum</c>.</summary>
public static TEnum ParseEnum<TEnum>(string value) where TEnum : struct {
return ParseEnum<TEnum>(value,true);
}
/// <summary>Typesafe wrapper for <c>Enum.ParseEnum()</c> that automatically checks
/// constants for membership in the <c>enum</c>.</summary>
public static TEnum ParseEnum<TEnum>(string value, bool checkConstants) where TEnum : struct {
TEnum enumValue;
if (!TryParseEnum<TEnum>(value, out enumValue) && checkConstants)
throw new ArgumentOutOfRangeException("value",value,"Enum type: " + typeof(TEnum).Name);
return enumValue;
}
/// <summary>Typesafe wrapper for <c>Enum.TryParseEnum()</c> that automatically checks
/// constants for membership in the <c>enum</c>.</summary>
public static bool TryParseEnum<TEnum>(string value, out TEnum enumValue) where TEnum : struct {
return Enum.TryParse<TEnum>(value, out enumValue)
&& Enum.IsDefined(typeof(TEnum),enumValue);
}
/// <summary>Typesafe wrapper for <c>Enum.ToObject()</c>.</summary>
/// <typeparam name="TEnum"></typeparam>
public static TEnum EnumParse<TEnum>(char c, string lookup) {
if (lookup==null) throw new ArgumentNullException("lookup");
var index = lookup.IndexOf(c);
if (index == -1) throw new ArgumentOutOfRangeException("c",c,"Enum Type: " + typeof(TEnum).Name);
return (TEnum) Enum.ToObject(typeof(TEnum), index);
}
#endregion
}
Using extension method we can create methods to convert an enum to other datatype like string, int by creating extension methods ToInt(), ToString(), etc for the enum.
I wonder how to implement the other way around, e.g. FromInt(int), FromString(string), etc. As far as I know I can't create MyEnum.FromInt() (static) extension method. So what are the possible approaches for this?
I would avoid polluting int or string with extension methods for enums, instead a good old fashioned static helper class might be in order.
public static class EnumHelper
{
public static T FromInt<T>(int value)
{
return (T)value;
}
public static T FromString<T>(string value)
{
return (T) Enum.Parse(typeof(T),value);
}
}
Do you really need those extension methods?
MyEnum fromInt = (MyEnum)someIntValue;
MyEnum fromString = (MyEnum)Enum.Parse(typeof(MyEnum), someStringValue, true);
int intFromEnum = (int)MyEnum.SomeValue;
string stringFromEnum = MyEnum.SomeValue.ToString();
The other way around would be possibly... the other way around ;) Extend int and string with generic extension methods which will take as type parameter the type of an enum:
public static TEnum ToEnum<TEnum>(this int val)
{
return (TEnum) System.Enum.ToObject(typeof(TEnum), val);
}
public static TEnum ToEnum<TEnum>(this string val)
{
return (TEnum) System.Enum.Parse(typeof(TEnum), val);
}
Usage:
var redFromInt = 141.ToEnum<System.Drawing.KnownColor>();
var redFromString = "Red".ToEnum<System.Drawing.KnownColor>();
There is unfortunately no generic constraint for Enums, so we have to check TEnum type during runtime; to simplify we'll leave that verification to Enum.ToObject and Enum.Parse methods.
why do you want FromInt an extenstion method versus just casting it?
MyEnum fromInt;
if(Enum.IsDefined(typeof(MyEnum), intvalue))
{
fromInt = (MyEnum) intvalue;
}
else
{
//not valid
}
alternatively, for strings, you can use Enum.TryParse
MyEnum fromString;
if (Enum.TryParse<MyEnum>(stringvalue, out fromString))
{
//succeeded
}
else
{
//not valid
}
Another approach (for the string part of your question):
/// <summary>
/// Static class for generic parsing of string to enum
/// </summary>
/// <typeparam name="T">Type of the enum to be parsed to</typeparam>
public static class Enum<T>
{
/// <summary>
/// Parses the specified value from string to the given Enum type.
/// </summary>
/// <param name="value">The value.</param>
/// <returns></returns>
public static T Parse(string value)
{
//Null check
if(value == null) throw new ArgumentNullException("value");
//Empty string check
value = value.Trim();
if(value.Length == 0) throw new ArgumentException("Must specify valid information for parsing in the string", "value");
//Not enum check
Type t = typeof(T);
if(!t.IsEnum) throw new ArgumentException("Type provided must be an Enum", "T");
return (T)Enum.Parse(typeof(T), value);
}
}
(Partially inspired by: http://devlicious.com/blogs/christopher_bennage/archive/2007/09/13/my-new-little-friend-enum-lt-t-gt.aspx)
You can do:
public static class EnumExtensions
{
public static Enum FromInt32(this Enum obj, Int32 value)
{
return (Enum)((Object)(value));
}
public static Enum FromString(this Enum obj, String value)
{
return (Enum)Enum.Parse(obj.GetType(), value);
}
}
Or:
public static class Int32Extensions
{
public static Enum ToEnum(this Int32 obj)
{
return (Enum)((Object)(obj));
}
}
public static class StringExtensions
{
public static Enum ToEnum(this Enum obj, String value)
{
return (Enum)Enum.Parse(obj.GetType(), value);
}
}
You can either make extension methods on int and string.
Or make static method on some other static class. Maybe something like EnumHelper.FromInt(int).
But I would pose one question : Why do you want to convert to string or int? Its not how you normaly work with enumerables, except maybe serialisation. But that should be handled by some kind of infrastructure, not your own code.
I have a DataGridView that I want to use to store generic data. I want to keep a typed data list in the DataGridView class so that all of the sorts, etc. can be handled internally. But I don't want to have to set the type on the DataGridView since I won't know the data type until the InitializeData method is called.
public class MyDataGridView : DataGridView {
private List<T> m_data;
public InitializeData<T>(List<T> data) {
m_data = data;
}
... internal events to know when the datagrid wants to sort ...
m_data.Sort<T>(...)
}
Is this possible? If so, how?
If you won't know the type until you call InitializeData, then the type clearly can't be a compile-time part of the object.
Do you know everything you need to know about the sorting when you call InitializeData<T>? If so, how about you do something like:
private IList m_data;
private Action m_sorter;
public InitializeData<T>(List<T> data)
{
m_data = data;
// This captures the data variable. You'll need to
// do something different if that's not good enough
m_sorter = () => data.Sort();
}
Then when you need to sort later, you can just call m_sorter().
If you might sort on different things, you could potentially change it from an Action to Action<string> or whatever you'd need to be able to sort on.
If Jon's answer isn't sufficient, here's a more general (but more involved, and probably somewhat more confusing) approach:
/// <summary>
/// Allows a list of any type to be used to get a result of type TResult
/// </summary>
/// <typeparam name="TResult">The result type after using the list</typeparam>
interface IListUser<TResult>
{
TResult Use<T>(List<T> list);
}
/// <summary>
/// Allows a list of any type to be used (with no return value)
/// </summary>
interface IListUser
{
void Use<T>(List<T> list);
}
/// <summary>
/// Here's a class that can sort lists of any type
/// </summary>
class GenericSorter : IListUser
{
#region IListUser Members
public void Use<T>(List<T> list)
{
// do generic sorting stuff here
}
#endregion
}
/// <summary>
/// Wraps a list of some unknown type. Allows list users (either with or without return values) to use the wrapped list.
/// </summary>
interface IExistsList
{
TResult Apply<TResult>(IListUser<TResult> user);
void Apply(IListUser user);
}
/// <summary>
/// Wraps a list of type T, hiding the type itself.
/// </summary>
/// <typeparam name="T">The type of element contained in the list</typeparam>
class ExistsList<T> : IExistsList
{
List<T> list;
public ExistsList(List<T> list)
{
this.list = list;
}
#region IExistsList Members
public TResult Apply<TResult>(IListUser<TResult> user)
{
return user.Use(list);
}
public void Apply(IListUser user)
{
user.Use(list);
}
#endregion
}
/// <summary>
/// Your logic goes here
/// </summary>
class MyDataGridView
{
private IExistsList list;
public void InitializeData<T>(List<T> list)
{
this.list = new ExistsList<T>(list);
}
public void Sort()
{
list.Apply(new GenericSorter());
}
}
You should define delgates or an interface for any generic operations you need to perform at runtime. As Jon Skeet mentioned, you can't strongly-type your data grid if you don't know the types at compile time.
This is the way the framework does it. For example:
Array.Sort();
Has a few ways it can be used:
Send it an array of objects that implement IComparable or IComparable<T>
Send in a second parameter, which is a class that implements IComparer or IComparer<T>. Used to compare the objects for sorting.
Send in a second parameter, which is a Comparison<T> delegate that can be used to compare objects in the array.
This is an example of how you approach the problem. At its most basic level, your scenario can be solved by a strategy pattern, which is what Array.Sort() does.
If you need to sort by things dynamically at run time, I would create an IComparer class that takes the column you want to sort by as an argument in its constructor. Then in your compare method, use that column as the sort type.
Here is an example of how you would do it using some basic example classes. Once you have these classes set up, then you'd pass both into your data grid and use them where appropriate.
public class Car
{
public string Make { get; set; }
public string Model { get; set; }
public string Year { get; set; }
}
public class CarComparer : IComparer
{
string sortColumn;
public CarComparer(string sortColumn)
{
this.sortColumn = sortColumn;
}
public int Compare(object x, object y)
{
Car carX = x as Car;
Car carY = y as Car;
if (carX == null && carY == null)
return 0;
if (carX != null && carY == null)
return 1;
if (carY != null && carX == null)
return -1;
switch (sortColumn)
{
case "Make":
return carX.Make.CompareTo(carY.Make);
case "Model":
return carX.Model.CompareTo(carY.Model);
case "Year":
default:
return carX.Year.CompareTo(carY.Year);
}
}
}