I have a small, fixed number of enums in their own .cs file in my custom namespace. Most of the enum names is the prefix of the corresponding table name in my SQLite database. As such, the string and int values in each enum are the record values for name and id respectively, therefore allowing me to easily keep track of which data to pass in methods that perform an SQL query.
public enum TableNamePrefix //respective table name would be "TableNamePrefix_SomeNameHere"
{
value1 = 1, //name = "value1", id = 1
value2 = 2, //name = "value2", id = 2
//...
}
public enum TableNamePrefix2
{
//...
}
//...
The goal is to simplify my database search criteria whenever I do a query which would heavily limit the chance of receiving a null record. Here is one of the methods I use to return a table row.
public static T GetTableRow(DBTableNameAbberviations tableNameAbb, Enum prefix,
string keyword = "", string name = "") //tableNameAbb is another enum
The method above works as expected, but I don't want Enum prefix to allow any Enum to be passed in, which brings me to my question. Is there a way to constrain this to a single or multiple user defined enums? In other words, rather than pass in any generic enum to my second parameter, is there a way to limit it to TableNamePrefix and my other omitted enums? If not, then what could a workaround be?
I thought about using a generic method with constraints, but where T2: System.Enum would still allow any Enum to be used.
You may consider using a type safe enum, since it seems you have additional data you want to accompany your enum.
This is the base class we will use for our type safe enums. It provides the basics for all type safe enums, the value and the name.
public abstract class TypeSafeEnumBase<TValue>
{
public readonly TValue Value;
public readonly string Name;
protected TypeSafeEnumBase(TValue value, string name)
{
this.Value = value;
this.Name = name;
}
public override string ToString()
{
return Name;
}
private static TypeSafeEnumBase<TValue>[] Items { get; set; }
public static IEnumerable<TypeSafeEnumBase<TValue>> GetValues<TType>()
{
if (Items == null || Items.Length == 0)
{
Dictionary<string, TType> items = typeof(TType)
.GetFields(BindingFlags.Public | BindingFlags.Static)
.Where(f => f.FieldType == typeof(TType))
.ToDictionary(f => f.Name,
f => (TType)f.GetValue(null));
Items = items.Values.Cast<TypeSafeEnumBase<TValue>>().ToArray();
}
foreach (TypeSafeEnumBase<TValue> item in Items)
{
yield return item;
}
}
}
This is your 'table details' setup as a type safe enum. In this class we implement any additional properties that may be needed, e.g. Prefix, Keyword, etc.
public sealed class TableDetails : TypeSafeEnumBase<int>
{
public static TableDetails TableOneDetails = new TableDetails(1, "value1", "TableNamePrefix1","table1keyword");
public static TableDetails TableTwoDetails = new TableDetails(2, "value2","TableNamePrefix2", "table2keyword");
public static TableDetails TableThreeDetails = new TableDetails(3, "value3", "TableNamePrefix3", "table3keyword");
public TableDetails(int value, string name, string prefix, string keyword) : base(value, name)
{
Prefix = prefix;
Keyword = keyword;
}
public string Prefix { get; }
public string Keyword { get; }
public static bool TryParse(int value, out TableDetails tableDetails)
{
return TryParse(value.ToString(), out tableDetails);
}
public static bool TryParse(string value, out TableDetails tableDetails)
{
try
{
tableDetails= Parse(value);
return true;
}
catch
{
tableDetails= null;
return false;
}
}
public static TableDetails Parse(int value)
{
return Parse(value.ToString());
}
public static TableDetails Parse(string value)
{
switch (value)
{
case "1":
case nameof(TableOneDetails):
return TableOneDetails;
case "2":
case nameof(TableTwoDetails):
return TableTwoDetails;
case "3":
case nameof(TableThreeDetails):
return TableThreeDetails;
default:
throw new IndexOutOfRangeException($"{nameof(TableDetails)} doesn't contain {value}.");
}
}
public override string ToString()
{
return base.Name;
}
}
You can now change your GetTableRow method to accept the type TableDetails. In addition you only have one parameter to pass in, the TableDetails, and if you need to add more parameters you can update your TableDetails object without having to change your GetTableRow method signature.
public static T GetTableRow(TableDetails tableDetails)
Contrain a type is difficult (unless it is a generic type), what you could do is create a type parameter on the method to the enum and constrain it to the enum type:
... GetTableRow<TEnum>(... TEnum prefix, ...) : where TEnum : EnumType {}
, or just throw an exception if enum is not the type you want.
I use a framework which exposes an abstract class called Value. Through operator overloading, it's possible to assign almost anything to this class's objects, and it works like a charm:
Value a = "hello";
Value b = 1;
Value c = true;
Value d = 3.14;
(Note that this is the only way to create instances of Value. There are no public/protected ways to assign values to instances, other than the overloaded operators.)
Right now, I want to override the implicit operator Value(string input) function, so that it XML-sanitizes any string before assigning it.
I have tried inheriting this class and overriding the operator, but have not found a way to feed the sanitized string into the base class's operator function. The following obviously doesn't work:
public override static implicit operator XmlValue(string input)
{
string output = sanitize(input);
XmlValue rv = null;
((Value)rv) = output; // this is not possible
return rv;
}
Is there a way to achieve this? Or alternatively, am I perhaps overthinking the problem and is there a better solution for what I want to do? In any case, I'd like to avoid having to sanitize each and every string before assigning it to a Value; this would be way too error prone.
FYI: the Value class is part of the Cottle framework.
The important point is that you cannot "override" operators, because they are static. You can instead define a new operator in your derived class, then make the assignment using a variable of your derived type (so that the compiler knows that it needs to call the operator of the derived class).
Look at this example:
using System;
class Value {
public string StringValue {
get;
private set;
}
protected Value(string str) {
StringValue = str;
}
public static implicit operator Value(string input) {
return new Value(input);
}
}
class XmlValue : Value {
protected XmlValue(string str) : base(str) {
}
public static implicit operator XmlValue(string input) {
// using "ToUpperInvariant" instead of sanitize
return new XmlValue(input.ToUpperInvariant());
}
}
class Program {
static void Main(string[] args) {
Value v1 = "test";
Console.WriteLine(v1.StringValue); // "test"
XmlValue v2 = "test";
Console.WriteLine(v2.StringValue); // "TEST"
}
}
After checking your comment, I think that the example below is more related to the real situation you are facing.
However, as fun as this operators overloading might be, I think that in this case you should definitely opt for the simpler and more readable solution of sanitizing every input before assignment.
using System;
abstract class Value {
public string StringValue {
get;
protected set;
}
public static implicit operator Value(string input) {
return new StringValue(input);
}
}
class StringValue : Value {
public StringValue(string str) {
StringValue = str;
}
}
class Xml {
string _value;
public Xml(string value) {
_value = value;
}
public static implicit operator Xml(string input) {
return new Xml(input.ToUpperInvariant());
}
public static implicit operator Value(Xml xml) {
Value ret = xml._value;
return ret;
}
}
class Program {
static void Main(string[] args) {
// this works with the cast operators...
Value v1 = (Xml)"test";
Console.WriteLine(v1.StringValue); // "TEST"
// ...but I would definitely go for this:
Value v2 = sanitize("test");
}
}
How can I use reflection to get the name and declaring class of a property of a generic type. The purpose is to get an exception if I read a property where nothing has been written so far. One of the problems is that the check must be independent of the declaring class.
value.GetType().DeclaringType is always null.
using System;
namespace TestCodeContract
{
public struct CheckForNull<T> where T : struct
{
private T? backingField;
public static implicit operator T(CheckForNull<T> value)
{
if (!(value.backingField.HasValue))
{
var t1 = value.GetType().DeclaringType; // always null.
var propertyName = "Delta"; // TODO get from Reflection
var className = "ContractClass"; // TODO get from Reflection
var msg = String.Format("Proprety '{0}' in class '{1}' is not initialized", propertyName, className);
throw new ApplicationException(msg);
}
return value.backingField.Value;
}
public static implicit operator CheckForNull<T>(T value)
{
return new CheckForNull<T> { backingField = value };
}
}
public class ContractClass
{
public CheckForNull<int> Delta { get; set; }
public void Test1()
{
int x = Delta; // Wanted: "Property 'Delta' in class 'ContractClass' is not initialized"
}
}
}
No, you can't do it like that. I would suggest something like this instead:
// You could do this without the constraint, with a bit of extra work.
public class ReadOnlyAfterWrite<T> where T : struct
{
private T? value;
private readonly string property;
private readonly string type;
public ReadOnlyAfterWrite(string property, string type)
{
this.property = property;
this.type = type;
}
public T Value
{
get
{
if (value == null)
{
// Use type and property here
throw new InvalidOperationException(...);
}
return (T) value;
}
set { this.value = value; }
}
}
public class ContractClass
{
// This is what I'd do in C# 6. Before that, probably just use string literals.
private readonly ReadOnlyAfterWrite<int> delta =
new ReadOnlyAfterWrite(nameof(Delta), nameof(ContractClass));
public int Delta
{
get { return delta.Value; }
set { delta.Value = value; }
}
}
While it's not terribly clean in implementation, I think it's a better public API - the fact that it's guarded is invisible to the caller, who just sees an int property.
How can I check whether a certain type implements a certain operator?
struct CustomOperatorsClass
{
public int Value { get; private set; }
public CustomOperatorsClass( int value )
: this()
{
Value = value;
}
static public CustomOperatorsClass operator +(
CustomOperatorsClass a, CustomOperatorsClass b )
{
return new CustomOperatorsClass( a.Value + b.Value );
}
}
Following two checks should return true:
typeof( CustomOperatorsClass ).HasOperator( Operator.Addition )
typeof( int ).HasOperator( Operator.Addition )
You should check if class have method with op_Addition name
You can find overloaded method names here,
Hope this helps
There is a quick and dirty way to find out, and it works for both built-in and custom types. Its major drawback is that it relies on exceptions in a normal flow, but it gets the job done.
static bool HasAdd<T>() {
var c = Expression.Constant(default(T), typeof(T));
try {
Expression.Add(c, c); // Throws an exception if + is not defined
return true;
} catch {
return false;
}
}
An extension method called HasAdditionOp like this:
pubilc static bool HasAdditionOp(this Type t)
{
var op_add = t.GetMethod("op_Addition");
return op_add != null && op_add.IsSpecialName;
}
Note that IsSpecialName prevents a normal method with the name "op_Addition";
I have an object that needs to be serialized to an EDI format. For this example we'll say it's a car. A car might not be the best example b/c options change over time, but for the real object the Enums will never change.
I have many Enums like the following with custom attributes applied.
public enum RoofStyle
{
[DisplayText("Glass Top")]
[StringValue("GTR")]
Glass,
[DisplayText("Convertible Soft Top")]
[StringValue("CST")]
ConvertibleSoft,
[DisplayText("Hard Top")]
[StringValue("HT ")]
HardTop,
[DisplayText("Targa Top")]
[StringValue("TT ")]
Targa,
}
The Attributes are accessed via Extension methods:
public static string GetStringValue(this Enum value)
{
// Get the type
Type type = value.GetType();
// Get fieldinfo for this type
FieldInfo fieldInfo = type.GetField(value.ToString());
// Get the stringvalue attributes
StringValueAttribute[] attribs = fieldInfo.GetCustomAttributes(
typeof(StringValueAttribute), false) as StringValueAttribute[];
// Return the first if there was a match.
return attribs.Length > 0 ? attribs[0].StringValue : null;
}
public static string GetDisplayText(this Enum value)
{
// Get the type
Type type = value.GetType();
// Get fieldinfo for this type
FieldInfo fieldInfo = type.GetField(value.ToString());
// Get the DisplayText attributes
DisplayTextAttribute[] attribs = fieldInfo.GetCustomAttributes(
typeof(DisplayTextAttribute), false) as DisplayTextAttribute[];
// Return the first if there was a match.
return attribs.Length > 0 ? attribs[0].DisplayText : value.ToString();
}
There is a custom EDI serializer that serializes based on the StringValue attributes like so:
StringBuilder sb = new StringBuilder();
sb.Append(car.RoofStyle.GetStringValue());
sb.Append(car.TireSize.GetStringValue());
sb.Append(car.Model.GetStringValue());
...
There is another method that can get Enum Value from StringValue for Deserialization:
car.RoofStyle = Enums.GetCode<RoofStyle>(EDIString.Substring(4, 3))
Defined as:
public static class Enums
{
public static T GetCode<T>(string value)
{
foreach (object o in System.Enum.GetValues(typeof(T)))
{
if (((Enum)o).GetStringValue() == value.ToUpper())
return (T)o;
}
throw new ArgumentException("No code exists for type " + typeof(T).ToString() + " corresponding to value of " + value);
}
}
And Finally, for the UI, the GetDisplayText() is used to show the user friendly text.
What do you think? Overkill? Is there a better way? or Goldie Locks (just right)?
Just want to get feedback before I intergrate it into my personal framework permanently. Thanks.
The part you're using to serialize is fine. The deserialization part is awkwardly written. The main problem is that you're using ToUpper() to compare strings, which is easily broken (think globalization). Such comparisons should be done with string.Compare instead, or the string.Equals overload that takes a StringComparison.
The other thing is that performing these lookups again and again during deserialization is going to pretty slow. If you're serializing a lot of data, this could actually be quite noticeable. In that case, you'd want to build a map from the StringValue to the enum itself - throw it into a static Dictionary<string, RoofStyle> and use it as a lookup for the round-trip. In other words:
public static class Enums
{
private static Dictionary<string, RoofStyle> roofStyles =
new Dictionary<string, RoofStyle>()
{
{ "GTR", RoofStyle.Glass },
{ "CST", RoofStyle.ConvertibleSoft },
{ "HT ", RoofStyle.HardTop },
{ "TT ", RoofStyle.TargaTop }
}
public static RoofStyle GetRoofStyle(string code)
{
RoofStyle result;
if (roofStyles.TryGetValue(code, out result))
return result;
throw new ArgumentException(...);
}
}
It's not as "generic" but it's way more efficient. If you don't like the duplication of string values then extract the codes as constants in a separate class.
If you really need it to be totally generic and work for any enum, you can always lazy-load the dictionary of values (generate it using the extension methods you've written) the first time a conversion is done. It's very simple to do that:
static Dictionary<string, T> CreateEnumLookup<T>()
{
return Enum.GetValues(typeof(T)).ToDictionary(o => ((Enum)o).GetStringValue(),
o => (T)o);
}
P.S. Minor detail but you might want to consider using Attribute.GetCustomAttribute instead of MemberInfo.GetCustomAttributes if you only expect there to be one attribute. There's no reason for all the array fiddling when you only need one item.
Personally, I think you are abusing the language and trying to use enums in a way they were never intended. I would create a static class RoofStyle, and create a simple struct RoofType, and use an instance for each of your enum values.
Why don't you create a type with static members such as mikerobi said
Example...
public class RoofStyle
{
private RoofStyle() { }
public string Display { get; private set; }
public string Value { get; private set; }
public readonly static RoofStyle Glass = new RoofStyle
{
Display = "Glass Top", Value = "GTR",
};
public readonly static RoofStyle ConvertibleSoft = new RoofStyle
{
Display = "Convertible Soft Top", Value = "CST",
};
public readonly static RoofStyle HardTop = new RoofStyle
{
Display = "Hard Top", Value = "HT ",
};
public readonly static RoofStyle Targa = new RoofStyle
{
Display = "Targa Top", Value = "TT ",
};
}
BTW...
When compiled into IL an Enum is very similar to this class structure.
... Enum backing fields ...
.field public specialname rtspecialname int32 value__
.field public static literal valuetype A.ERoofStyle Glass = int32(0x00)
.field public static literal valuetype A.ERoofStyle ConvertibleSoft = int32(0x01)
.field public static literal valuetype A.ERoofStyle HardTop = int32(0x02)
.field public static literal valuetype A.ERoofStyle Targa = int32(0x03)
... Class backing fields ...
.field public static initonly class A.RoofStyle Glass
.field public static initonly class A.RoofStyle ConvertibleSoft
.field public static initonly class A.RoofStyle HardTop
.field public static initonly class A.RoofStyle Targa
Here is a base class I use for enumeration classes:
public abstract class Enumeration<T, TId> : IEquatable<T> where T : Enumeration<T, TId>
{
public static bool operator ==(Enumeration<T, TId> x, T y)
{
return Object.ReferenceEquals(x, y) || (!Object.ReferenceEquals(x, null) && x.Equals(y));
}
public static bool operator !=(Enumeration<T, TId> first, T second)
{
return !(first == second);
}
public static T FromId(TId id)
{
return AllValues.Where(value => value.Id.Equals(id)).FirstOrDefault();
}
public static readonly ReadOnlyCollection<T> AllValues = FindValues();
private static ReadOnlyCollection<T> FindValues()
{
var values =
(from staticField in typeof(T).GetFields(BindingFlags.Static | BindingFlags.Public)
where staticField.FieldType == typeof(T)
select (T) staticField.GetValue(null))
.ToList()
.AsReadOnly();
var duplicateIds =
(from value in values
group value by value.Id into valuesById
where valuesById.Skip(1).Any()
select valuesById.Key)
.Take(1)
.ToList();
if(duplicateIds.Count > 0)
{
throw new DuplicateEnumerationIdException("Duplicate ID: " + duplicateIds.Single());
}
return values;
}
protected Enumeration(TId id, string name)
{
Contract.Requires(((object) id) != null);
Contract.Requires(!String.IsNullOrEmpty(name));
this.Id = id;
this.Name = name;
}
protected Enumeration()
{}
public override bool Equals(object obj)
{
return Equals(obj as T);
}
public override int GetHashCode()
{
return this.Id.GetHashCode();
}
public override string ToString()
{
return this.Name;
}
#region IEquatable
public virtual bool Equals(T other)
{
return other != null && this.IdComparer.Equals(this.Id, other.Id);
}
#endregion
public virtual TId Id { get; private set; }
public virtual string Name { get; private set; }
protected virtual IEqualityComparer<TId> IdComparer
{
get { return EqualityComparer<TId>.Default; }
}
}
An implementation would look like:
public sealed class RoofStyle : Enumeration<RoofStyle, int>
{
public static readonly RoofStyle Glass = new RoofStyle(0, "Glass Top", "GTR");
public static readonly RoofStyle ConvertibleSoft = new RoofStyle(1, "Convertible Soft Top", "CST");
public static readonly RoofStyle HardTop = new RoofStyle(2, "Hard Top", "HT ");
public static readonly RoofStyle Targa = new RoofStyle(3, "Targa Top", "TT ");
public static RoofStyle FromStringValue(string stringValue)
{
return AllValues.FirstOrDefault(value => value.StringValue == stringValue);
}
private RoofStyle(int id, string name, string stringValue) : base(id, name)
{
StringValue = stringValue;
}
public string StringValue { get; private set; }
}
You would use it during serialization like this:
var builder = new StringBuilder();
builder.Append(car.RoofStyle.StringValue);
...
To deserialize:
car.RoofStyle = RoofStyle.FromStringValue(EDIString.Substring(4, 3));
I don't see a problem with it - actually, I do the same. By this, I achieve verbosity with the enum, and can define how the enum is to be translated when I use it to request data, eg. RequestTarget.Character will result in "char".
Can't say I've ever seen it done that way but the consumer code is relatively simple so I'd probably enjoy using it.
The only thing that sticks out for me is the potential for consumers having to deal with nulls - which might be able to be removed. If you have control over the attributes (which you do, from the sounds of it), then there should never be a case where GetDisplayText or GetStringValue return null so you can remove
return attribs.Length > 0 ? attribs[0].StringValue : null;
and replace it with
return attribs[0].StringValue;
in order to simplify the interface for consumer code.
IMHO, the design is solid, and will work.
However, reflection tends to be a litle slow, so if those methods are used in tight loops, it might slow down the whole application.
You could try caching the the return values into a Dictionary<RoofStyle, string> so they are only reflected once, and then fetched from cache.
Something like this:
private static Dictionary<Enum, string> stringValues
= new Dictionary<Enum,string>();
public static string GetStringValue(this Enum value)
{
if (!stringValues.ContainsKey(value))
{
Type type = value.GetType();
FieldInfo fieldInfo = type.GetField(value.ToString());
StringValueAttribute[] attribs = fieldInfo.GetCustomAttributes(
typeof(StringValueAttribute), false) as StringValueAttribute[];
stringValues.Add(value, attribs.Length > 0 ? attribs[0].StringValue : null);
}
return stringValues[value];
}
I know this question has already been answered, but while ago I posted the following code fragment on my personal blog, which demonstrates faking Java style enums using extension methods. You might find this method works for you, especially as it overcomes the overhead of accessing Attributes via reflection.
using System;
using System.Collections.Generic;
namespace ScratchPad
{
internal class Program
{
private static void Main(string[] args)
{
var p = new Program();
p.Run();
}
private void Run()
{
double earthWeight = 175;
double mass = earthWeight / Planet.Earth.SurfaceGravity();
foreach (Planet planet in Enum.GetValues(typeof(Planet))) {
Console.WriteLine("Your weight on {0} is {1}", planet, planet.SurfaceWeight(mass));
}
}
}
public enum Planet
{
Mercury,
Venus,
Earth,
Mars,
Jupiter,
Saturn,
Uranus,
Neptune
}
public static class PlanetExtensions
{
private static readonly Dictionary<Planet, PlanetData> planetMap = new Dictionary<Planet, PlanetData>
{
{Planet.Mercury, new PlanetData(3.303e+23, 2.4397e6)},
{Planet.Venus, new PlanetData(4.869e+24, 6.0518e6)},
{Planet.Earth, new PlanetData(5.976e+24, 6.37814e6)},
{Planet.Mars, new PlanetData(6.421e+23, 3.3972e6)},
{Planet.Jupiter, new PlanetData(1.9e+27, 7.1492e7)},
{Planet.Saturn, new PlanetData(5.688e+26, 6.0268e7)},
{Planet.Uranus, new PlanetData(8.686e+25, 2.5559e7)},
{Planet.Neptune, new PlanetData(1.024e+26, 2.4746e7)}
};
private const double G = 6.67300E-11;
public static double Mass(this Planet planet)
{
return GetPlanetData(planet).Mass;
}
public static double Radius(this Planet planet)
{
return GetPlanetData(planet).Radius;
}
public static double SurfaceGravity(this Planet planet)
{
PlanetData planetData = GetPlanetData(planet);
return G * planetData.Mass / (planetData.Radius * planetData.Radius);
}
public static double SurfaceWeight(this Planet planet, double mass)
{
return mass * SurfaceGravity(planet);
}
private static PlanetData GetPlanetData(Planet planet)
{
if (!planetMap.ContainsKey(planet))
throw new ArgumentOutOfRangeException("planet", "Unknown Planet");
return planetMap[planet];
}
#region Nested type: PlanetData
public class PlanetData
{
public PlanetData(double mass, double radius)
{
Mass = mass;
Radius = radius;
}
public double Mass { get; private set; }
public double Radius { get; private set; }
}
#endregion
}
}