I'm sure this is fairly trivial but I can't get it right.
public static string DoSomething(this Enum value)
{
if (!Enum.IsDefined(value.GetType(), value))
{
// not a valid value, assume default value
value = default(value.GetType());
}
// ... do some other stuff
}
The line value = default(value.GetType()); doesn't compile, but hopefully you can see what I'm attempting. I need to set the Enum param to the default value of it's own type.
I'm not really sure what you're trying to do here, but a version of the 'default' line which does compile is this:
value = (Enum)Enum.GetValues(value.GetType()).GetValue(0);
Or, even cleaner (from Paw, in the comments, thanks):
value = (Enum) Enum.ToObject(value.GetType(), 0);
This second version does only work properly if you know the enum's first element has a value of zero.
You actually could do what Paw is suggesting, even with a generic constraint, if you could move this method to its own class:
public abstract class Helper<T>
{
public static string DoSomething<TEnum>(TEnum value) where TEnum: struct, T
{
if (!Enum.IsDefined(typeof(TEnum), value))
{
value = default(TEnum);
}
// ... do some other stuff
// just to get code to compile
return value.ToString();
}
}
public class EnumHelper : Helper<Enum> { }
Then you would do, for example:
MyEnum x = MyEnum.SomeValue;
MyEnum y = (MyEnum)100; // Let's say this is undefined.
EnumHelper.DoSomething(x); // generic type of MyEnum can be inferred
EnumHelper.DoSomething(y); // same here
As Konrad Rudolph points out in a comment, default(TEnum) in the above code will evaluate to 0, regardless of whether or not a value is defined for 0 for the given TEnum type. If that's not what you want, Will's answer provides certainly the easiest way of getting the first defined value ((TEnum)Enum.GetValues(typeof(TEnum)).GetValue(0)).
On the other hand, if you want to take this to the extreme, and cache the result so that you don't always have to box it, you could do that:
public abstract class Helper<T>
{
static Dictionary<Type, T> s_defaults = new Dictionary<Type, T>();
public static string DoSomething<TEnum>(TEnum value) where TEnum: struct, T
{
if (!Enum.IsDefined(typeof(TEnum), value))
{
value = GetDefault<TEnum>();
}
// ... do some other stuff
// just to get code to compile
return value.ToString();
}
public static TEnum GetDefault<TEnum>() where TEnum : struct, T
{
T definedDefault;
if (!s_defaults.TryGetValue(typeof(TEnum), out definedDefault))
{
// This is the only time you'll have to box the defined default.
definedDefault = (T)Enum.GetValues(typeof(TEnum)).GetValue(0);
s_defaults[typeof(TEnum)] = definedDefault;
}
// Every subsequent call to GetDefault on the same TEnum type
// will unbox the same object.
return (TEnum)definedDefault;
}
}
Activator.CreateInstance(typeof(ConsoleColor)) seems to work
Enum by default have its first value as default value
Have you thought about making it a generic method?
public static string DoSomething<T>(Enum value)
{
if (!Enum.IsDefined(typeof(T), value))
{
value = (T)Enum.ToObject(typeof(T), 0);
}
// ... do some other stuff
}
The caller of the method should know the type.
Related
I'd like to use a certain operation for multiple variable types (both native and objects) so I'm using the generic return type as follows.
private Generic Field<Generic>(String field)
{
if (BagOfJunk.Properties.Contains(field))
return (Generic)BagOfJunk[field];
return default(Generic);
}
This works well (and BagOfJunk is just a property of this from which I'm pulling out Object typed values). Now, during run-time, when a field isn't contained in the bag, I get the default value to be null. Hence, in the code, I need to perform a check as follows.
NumericType protoNumber = Field<NumericType>("beep");
int number = protoNumber != null ? protoNumber.Value : -1;
DateType protoDate = Field<DateType>("boop");
DateTime date = protoDate != null ? protoDate.Value : null;
I'd like to make the code more compact, so I tried to design a method that does the above four lines in one swoop, for a generic type. The result is below but, of course, it doesn't compile, because the type GenericIn isn't specific enough to have a property Value.
private GenericOut Field<GenericIn, GenericOut>(String field)
{
GenericIn input = Field<GenericIn>(field);
if (input != null)
return (GenericOut)input.Value;
return default(GenericOut);
}
How can I ensure the computer that my GenericIn isn't general - by promising that whatever stuff I'll shove into it, it'll always have the property Value in it?
Edit
It should be emphasized that the type of Value needs to be generic ( equivalent to GenericOut). I noticed that I didn't stress that strongly enough. So the interface that can be used need to declare a property of general type like the following.
interface ObjectWithValue { public Generic Value { get; } }
You can use an interface and apply a where constraint on the type to implement that interface, like below:
interface IHasPropertyValue<TValue> {
TValue Value { get; }
}
class MyType {
public TValue Method<T, TValue>(T obj) where T : IHasPropertyValue<TValue> {
return obj.Value;
}
}
EDIT: Modified the code above to make it more specific to the comment asked below.
put that property in an interface (or a class) and use the generic constraint "where":
public interface IMyInterface
{
public object Value { get; set; }
}
public class C<T> where T:IMyInterface
To build upon the answers so far, you need to create an interface that will be implemented by your GenericIn that will both guarantee that it has a property Value and that the property is of type GenericOut.
interface IHasValue<TOut>
{
TOut Value { get; }
}
private TOut Field<TIn, TOut>(string field) where TIn : IHasValue<TOut>
{
var input = Field<TIn>(field);
return input == null ? default(TOut) : input.Value;
}
I have an enum
enum myEnum2 { ab, st, top, under, below}
I would like to write a function to test if a given value is included in myEnum
something like that:
private bool EnumContainValue(Enum myEnum, string myValue)
{
return Enum.GetValues(typeof(myEnum))
.ToString().ToUpper().Contains(myValue.ToUpper());
}
But it doesn't work because myEnum parameter is not recognized.
Why not use
Enum.IsDefined(typeof(myEnum), value);
BTW it's nice to create generic Enum<T> class, which wraps around calls to Enum (actually I wonder why something like this was not added to Framework 2.0 or later):
public static class Enum<T>
{
public static bool IsDefined(string name)
{
return Enum.IsDefined(typeof(T), name);
}
public static bool IsDefined(T value)
{
return Enum.IsDefined(typeof(T), value);
}
public static IEnumerable<T> GetValues()
{
return Enum.GetValues(typeof(T)).Cast<T>();
}
// etc
}
This allows to avoid all this typeof stuff and use strongly-typed values:
Enum<StringSplitOptions>.IsDefined("None")
No need to write your own:
// Summary:
// Returns an indication whether a constant with a specified value exists in
// a specified enumeration.
//
// Parameters:
// enumType:
// An enumeration type.
//
// value:
// The value or name of a constant in enumType.
//
// Returns:
// true if a constant in enumType has a value equal to value; otherwise, false.
public static bool IsDefined(Type enumType, object value);
Example:
if (System.Enum.IsDefined(MyEnumType, MyValue))
{
// Do something
}
just use this method
Enum.IsDefined Method - Returns an indication whether a constant with a specified value exists in a specified enumeration
Example
enum myEnum2 { ab, st, top, under, below};
myEnum2 value = myEnum2.ab;
Console.WriteLine("{0:D} Exists: {1}",
value, myEnum2.IsDefined(typeof(myEnum2), value));
What you're doing with ToString() in this case is to:
Enum.GetValues(typeof(myEnum)).ToString()... instead you should write:
Enum.GetValues(typeof(myEnum).ToString()...
The difference is in the parentheses...
Also can use this:
enum myEnum2 { ab, st, top, under, below }
static void Main(string[] args)
{
myEnum2 r;
string name = "ab";
bool result = Enum.TryParse(name, out r);
}
The result will contain whether the value is contained in enum or not.
public static T ConvertToEnum<T>(this string value)
{
if (typeof(T).BaseType != typeof(Enum))
{
throw new InvalidCastException("The specified object is not an enum.");
}
if (Enum.IsDefined(typeof(T), value.ToUpper()) == false)
{
throw new InvalidCastException("The parameter value doesn't exist in the specified enum.");
}
return (T)Enum.Parse(typeof(T), value.ToUpper());
}
If your question is like "I have an enum type, enum MyEnum { OneEnumMember, OtherEnumMember }, and I'd like to have a function which tells whether this enum type contains a member with a specific name, then what you're looking for is the System.Enum.IsDefined method:
Enum.IsDefined(typeof(MyEnum), MyEnum.OneEnumMember); //returns true
Enum.IsDefined(typeof(MyEnum), "OtherEnumMember"); //returns true
Enum.IsDefined(typeof(MyEnum), "SomethingDifferent"); //returns false
If your question is like "I have an instance of an enum type, which has Flags attribute, and I'd like to have a function which tells whether this instance contains a specific enum value, then the function looks something like this:
public static bool ContainsValue<TEnum>(this TEnum e, TEnum val) where Enum: struct, IComparable, IFormattable, IConvertible
{
if (!e.GetType().IsEnum)
throw new ArgumentException("The type TEnum must be an enum type.", nameof(TEnum));
dynamic val1 = e, val2 = val;
return (val1 | val2) == val1;
}
Hope I could help.
Use the correct name of the enum (myEnum2).
Also, if you're testing against a string value you may want to use GetNames instead of GetValues.
just cast the enum as:
string something = (string)myEnum;
and now comparison is easy as you like
I think that you go wrong when using ToString().
Try making a Linq query
private bool EnumContainValue(Enum myEnum, string myValue)
{
var query = from enumVal in Enum.GetNames(typeof(GM)).ToList()
where enumVal == myValue
select enumVal;
return query.Count() == 1;
}
Is there a way to make this method generic so I can return a string, bool, int, or double? Right now, it's returning a string, but if it's able find "true" or "false" as the configuration value, I'd like to return a bool for example.
public static string ConfigSetting(string settingName)
{
return ConfigurationManager.AppSettings[settingName];
}
You need to make it a generic method, like this:
public static T ConfigSetting<T>(string settingName)
{
return /* code to convert the setting to T... */
}
But the caller will have to specify the type they expect. You could then potentially use Convert.ChangeType, assuming that all the relevant types are supported:
public static T ConfigSetting<T>(string settingName)
{
object value = ConfigurationManager.AppSettings[settingName];
return (T) Convert.ChangeType(value, typeof(T));
}
I'm not entirely convinced that all this is a good idea, mind you...
You could use Convert.ChangeType():
public static T ConfigSetting<T>(string settingName)
{
return (T)Convert.ChangeType(ConfigurationManager.AppSettings[settingName], typeof(T));
}
There are many ways of doing this(listed by priority, specific to the OP's problem)
Option 1: Straight approach - Create multiple functions for each type you expect rather than having one generic function.
public static bool ConfigSettingInt(string settingName)
{
return Convert.ToBoolean(ConfigurationManager.AppSettings[settingName]);
}
Option 2: When you don't want to use fancy methods of conversion - Cast the value to object and then to generic type.
public static T ConfigSetting<T>(string settingName)
{
return (T)(object)ConfigurationManager.AppSettings[settingName];
}
Note - This will throw an error if the cast is not valid(your case). I would not recommend doing this if you are not sure about the type casting, rather go for option 3.
Option 3: Generic with type safety - Create a generic function to handle type conversion.
public static T ConvertValue<T,U>(U value) where U : IConvertible
{
return (T)Convert.ChangeType(value, typeof(T));
}
Note - T is the expected type, note the where constraint here(type of U must be IConvertible to save us from the errors)
You have to convert the type of your return value of the method to the Generic type which you pass to the method during calling.
public static T values<T>()
{
Random random = new Random();
int number = random.Next(1, 4);
return (T)Convert.ChangeType(number, typeof(T));
}
You need pass a type that is type casteable for the value you return through that method.
If you would want to return a value which is not type casteable to the generic type you pass, you might have to alter the code or make sure you pass a type that is casteable for the return value of method. So, this approach is not reccomended.
Create a function and pass output parameter as of generic type.
public static T some_function<T>(T output_object /*declare as Output object*/)
{
return output_object;
}
Please try below code :
public T? GetParsedOrDefaultValue<T>(string valueToParse) where T : struct, IComparable
{
if(string.EmptyOrNull(valueToParse))return null;
try
{
// return parsed value
return (T) Convert.ChangeType(valueToParse, typeof(T));
}
catch(Exception)
{
//default as null value
return null;
}
return null;
}
private static T[] prepareArray<T>(T[] arrayToCopy, T value)
{
Array.Copy(arrayToCopy, 1, arrayToCopy, 0, arrayToCopy.Length - 1);
arrayToCopy[arrayToCopy.Length - 1] = value;
return (T[])arrayToCopy;
}
I was performing this throughout my code and wanted a way to put it into a method. I wanted to share this here because I didn't have to use the Convert.ChangeType for my return value. This may not be a best practice but it worked for me. This method takes in an array of generic type and a value to add to the end of the array. The array is then copied with the first value stripped and the value taken into the method is added to the end of the array. The last thing is that I return the generic array.
I have some methods like the following:
static public int GetInt(int _default = 0)
{
// do work, return _default if error
}
static public int? GetInt(int? _default = null)
{
// do work, return _default if error
}
I was hoping when using these methods as overrides that the method would be chosen also based on the variable I am using them to assign to:
int value1 = GetInt();
int? value2 = GetInt();
However this results in an "Ambiguous Invocation" error.
What can I do to avoid this?
The problem is that the return type is not part the signature of a method in C#. So you have to name the methods differently. Also, don't use underscore in parameter names.
To quote MSDN on how method signatures work:
The signature of a method consists of the name of the method and the
type and kind (value, reference, or output) of each of its formal
parameters, considered in the order left to right. The signature of a
method specifically does not include the return type, nor does it
include the params modifier that may be specified for the right-most
parameter.
This is a way to resolve it. As you return the default of the type, you can just make it generic and use default(T).
static void Main(string[] args)
{
int value1 = GetInt<int>();
int? value2 = GetInt<int?>();
}
static public T GetInt<T>(T defaultValue = default(T))
{
bool error = true;
if (error)
{
return defaultValue;
}
else
{
//yadayada
return something else;
}
}
Switch architecture.
static public T GetInt<T>(T defaultValue = default(T))
where T: struct
{
// Do Work.
// On failure
return defaultValue;
}
Then, when you call the function, you should benefit from the generic type:
int value1 = GetInt(0);
int? value2 = GetInt(default(int?));
Or if you want to omit the default value:
int value1 = GetInt<int>();
int? value2 = GetInt<int?>();
Alternatively, if you just want the default value, you can simply return
return default(T);
UPDATE: Added constraint - obviously, the problem with making it generic is then you can supply any type; however, your problem then becomes making it compliant to turn an integer into T.
What I want to do is something like this: I have enums with combined flagged values.
public static class EnumExtension
{
public static bool IsSet<T>( this T input, T matchTo )
where T:enum //the constraint I want that doesn't exist in C#3
{
return (input & matchTo) != 0;
}
}
So then I could do:
MyEnum tester = MyEnum.FlagA | MyEnum.FlagB
if( tester.IsSet( MyEnum.FlagA ) )
//act on flag a
Unfortunately, C#'s generic where constraints have no enum restriction, only class and struct. C# doesn't see enums as structs (even though they are value types) so I can't add extension types like this.
Does anyone know a workaround?
EDIT: This is now live in version 0.0.0.2 of UnconstrainedMelody.
(As requested on my blog post about enum constraints. I've included the basic facts below for the sake of a standalone answer.)
The best solution is to wait for me to include it in UnconstrainedMelody1. This is a library which takes C# code with "fake" constraints such as
where T : struct, IEnumConstraint
and turns it into
where T : struct, System.Enum
via a postbuild step.
It shouldn't be too hard to write IsSet... although catering for both Int64-based and UInt64-based flags could be the tricky part. (I smell some helper methods coming on, basically allowing me to treat any flags enum as if it had a base type of UInt64.)
What would you want the behaviour to be if you called
tester.IsSet(MyFlags.A | MyFlags.C)
? Should it check that all the specified flags are set? That would be my expectation.
I'll try to do this on the way home tonight... I'm hoping to have a quick blitz on useful enum methods to get the library up to a usable standard quickly, then relax a bit.
EDIT: I'm not sure about IsSet as a name, by the way. Options:
Includes
Contains
HasFlag (or HasFlags)
IsSet (it's certainly an option)
Thoughts welcome. I'm sure it'll be a while before anything's set in stone anyway...
1 or submit it as a patch, of course...
As of C# 7.3, there is now a built-in way to add enum constraints:
public class UsingEnum<T> where T : System.Enum { }
source: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/where-generic-type-constraint
Darren, that would work if the types were specific enumerations - for general enumerations to work you have to cast them to ints (or more likely uint) to do the boolean math:
public static bool IsSet( this Enum input, Enum matchTo )
{
return ( Convert.ToUInt32( input ) & Convert.ToUInt32( matchTo ) ) != 0;
}
As of C# 7.3, you can use the Enum constraint on generic types:
public static TEnum Parse<TEnum>(string value) where TEnum : Enum
{
return (TEnum) Enum.Parse(typeof(TEnum), value);
}
If you want to use a Nullable enum, you must leave the orginial struct constraint:
public static TEnum? TryParse<TEnum>(string value) where TEnum : struct, Enum
{
if( Enum.TryParse(value, out TEnum res) )
return res;
else
return null;
}
Actually, it is possible, with an ugly trick.
However, it cannot be used for extension methods.
public abstract class Enums<Temp> where Temp : class {
public static TEnum Parse<TEnum>(string name) where TEnum : struct, Temp {
return (TEnum)Enum.Parse(typeof(TEnum), name);
}
}
public abstract class Enums : Enums<Enum> { }
Enums.IsSet<DateTimeKind>("Local")
If you want to, you can give Enums<Temp> a private constructor and a public nested abstract inherited class with Temp as Enum, to prevent inherited versions for non-enums.
You can achieve this using IL Weaving and ExtraConstraints
Allows you to write this code
public class Sample
{
public void MethodWithDelegateConstraint<[DelegateConstraint] T> ()
{
}
public void MethodWithEnumConstraint<[EnumConstraint] T>()
{
}
}
What gets compiled
public class Sample
{
public void MethodWithDelegateConstraint<T>() where T: Delegate
{
}
public void MethodWithEnumConstraint<T>() where T: struct, Enum
{
}
}
This doesn't answer the original question, but there is now a method in .NET 4 called Enum.HasFlag which does what you are trying to do in your example
The way I do it is put a struct constraint, then check that T is an enum at runtime. This doesn't eliminate the problem completely, but it does reduce it somewhat
Using your original code, inside the method you can also use reflection to test that T is an enum:
public static class EnumExtension
{
public static bool IsSet<T>( this T input, T matchTo )
{
if (!typeof(T).IsEnum)
{
throw new ArgumentException("Must be an enum", "input");
}
return (input & matchTo) != 0;
}
}
Here's some code that I just did up that seems to work like you want without having to do anything too crazy. It's not restricted to only enums set as Flags, but there could always be a check put in if need be.
public static class EnumExtensions
{
public static bool ContainsFlag(this Enum source, Enum flag)
{
var sourceValue = ToUInt64(source);
var flagValue = ToUInt64(flag);
return (sourceValue & flagValue) == flagValue;
}
public static bool ContainsAnyFlag(this Enum source, params Enum[] flags)
{
var sourceValue = ToUInt64(source);
foreach (var flag in flags)
{
var flagValue = ToUInt64(flag);
if ((sourceValue & flagValue) == flagValue)
{
return true;
}
}
return false;
}
// found in the Enum class as an internal method
private static ulong ToUInt64(object value)
{
switch (Convert.GetTypeCode(value))
{
case TypeCode.SByte:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
return (ulong)Convert.ToInt64(value, CultureInfo.InvariantCulture);
case TypeCode.Byte:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
return Convert.ToUInt64(value, CultureInfo.InvariantCulture);
}
throw new InvalidOperationException("Unknown enum type.");
}
}
if someone needs generic IsSet (created out of box on fly could be improved on), and or string to Enum onfly conversion (which uses EnumConstraint presented below):
public class TestClass
{ }
public struct TestStruct
{ }
public enum TestEnum
{
e1,
e2,
e3
}
public static class TestEnumConstraintExtenssion
{
public static bool IsSet<TEnum>(this TEnum _this, TEnum flag)
where TEnum : struct
{
return (((uint)Convert.ChangeType(_this, typeof(uint))) & ((uint)Convert.ChangeType(flag, typeof(uint)))) == ((uint)Convert.ChangeType(flag, typeof(uint)));
}
//public static TestClass ToTestClass(this string _this)
//{
// // #generates compile error (so no missuse)
// return EnumConstraint.TryParse<TestClass>(_this);
//}
//public static TestStruct ToTestStruct(this string _this)
//{
// // #generates compile error (so no missuse)
// return EnumConstraint.TryParse<TestStruct>(_this);
//}
public static TestEnum ToTestEnum(this string _this)
{
// #enum type works just fine (coding constraint to Enum type)
return EnumConstraint.TryParse<TestEnum>(_this);
}
public static void TestAll()
{
TestEnum t1 = "e3".ToTestEnum();
TestEnum t2 = "e2".ToTestEnum();
TestEnum t3 = "non existing".ToTestEnum(); // default(TestEnum) for non existing
bool b1 = t3.IsSet(TestEnum.e1); // you can ommit type
bool b2 = t3.IsSet<TestEnum>(TestEnum.e2); // you can specify explicite type
TestStruct t;
// #generates compile error (so no missuse)
//bool b3 = t.IsSet<TestEnum>(TestEnum.e1);
}
}
If someone still needs example hot to create Enum coding constraint:
using System;
/// <summary>
/// would be same as EnumConstraint_T<Enum>Parse<EnumType>("Normal"),
/// but writen like this it abuses constrain inheritence on System.Enum.
/// </summary>
public class EnumConstraint : EnumConstraint_T<Enum>
{
}
/// <summary>
/// provides ability to constrain TEnum to System.Enum abusing constrain inheritence
/// </summary>
/// <typeparam name="TClass">should be System.Enum</typeparam>
public abstract class EnumConstraint_T<TClass>
where TClass : class
{
public static TEnum Parse<TEnum>(string value)
where TEnum : TClass
{
return (TEnum)Enum.Parse(typeof(TEnum), value);
}
public static bool TryParse<TEnum>(string value, out TEnum evalue)
where TEnum : struct, TClass // struct is required to ignore non nullable type error
{
evalue = default(TEnum);
return Enum.TryParse<TEnum>(value, out evalue);
}
public static TEnum TryParse<TEnum>(string value, TEnum defaultValue = default(TEnum))
where TEnum : struct, TClass // struct is required to ignore non nullable type error
{
Enum.TryParse<TEnum>(value, out defaultValue);
return defaultValue;
}
public static TEnum Parse<TEnum>(string value, TEnum defaultValue = default(TEnum))
where TEnum : struct, TClass // struct is required to ignore non nullable type error
{
TEnum result;
if (Enum.TryParse<TEnum>(value, out result))
return result;
return defaultValue;
}
public static TEnum Parse<TEnum>(ushort value)
{
return (TEnum)(object)value;
}
public static sbyte to_i1<TEnum>(TEnum value)
{
return (sbyte)(object)Convert.ChangeType(value, typeof(sbyte));
}
public static byte to_u1<TEnum>(TEnum value)
{
return (byte)(object)Convert.ChangeType(value, typeof(byte));
}
public static short to_i2<TEnum>(TEnum value)
{
return (short)(object)Convert.ChangeType(value, typeof(short));
}
public static ushort to_u2<TEnum>(TEnum value)
{
return (ushort)(object)Convert.ChangeType(value, typeof(ushort));
}
public static int to_i4<TEnum>(TEnum value)
{
return (int)(object)Convert.ChangeType(value, typeof(int));
}
public static uint to_u4<TEnum>(TEnum value)
{
return (uint)(object)Convert.ChangeType(value, typeof(uint));
}
}
hope this helps someone.
I just wanted to add Enum as a generic constraint.
While this is just for a tiny helper method using ExtraConstraints is a bit too much overhead for me.
I decided to just just create a struct constraint and add a runtime check for IsEnum. For converting a variable from T to Enum I cast it to object first.
public static Converter<T, string> CreateConverter<T>() where T : struct
{
if (!typeof(T).IsEnum) throw new ArgumentException("Given Type is not an Enum");
return new Converter<T, string>(x => ((Enum)(object)x).GetEnumDescription());
}