Using an Enum as an Attribute Argument - c#

Here is the code I would like to use:
public enum Days { Sat = 1, Sun, Mon, Tue, Wed, Thu, Fri };
[EnumHelper(typeof(Days))]
public Days DayOfWeek { get; set; }
EnumHelper looks like:
[AttributeUsage(AttributeTargets.Property,AllowMultiple=true)]
public class EnumHelper : Attribute
{
public Type MyEnum { get; set; }
public EnumHelper(Type enum)
{
MyEnum = enum;
}
}
The error I get on EnumHelper(Days) is that "Enum Name not valid at this point". Am I doing something wrong, or can this not be done?
MORE INFO
I am trying to pass the Enum (Days), and randomly get back one of the values.

You're trying to pass a type name as if it were an argument value. You can't do that. However, you can do:
[AttributeUsage(AttributeTargets.Property,AllowMultiple=true)]
public class EnumHelper : Attribute
{
public Type EnumType;
public EnumHelper(Type enumType)
{
EnumType = enumType;
}
}
...
[EnumHelper(typeof(Days))]
public Days DayOfWeek { get; set; }
However:
I wouldn't personally make EnumType a public field; make it a property.
There's currently no validation that EnumType is actually an enum. You can't do it at compile-time, but you could do it at execution time.
For the sake of convention, it should be called EnumHelperAttribute (or something more descriptive, really) - this isn't causing the error, but it's more idiomatic
I'm not really sure I see the benefit... you can find the type of the property from the metadata already; what do you think the attribute is actually buying you?
If you could let us know what you're trying to accomplish, we may be able to be more useful to you.

The parameters in Attributes can be only constants.
If you want pass the enum type you must pass only the type:
[EnumHelper(typeof(Days))]
public Days DayOfWeek { get; set; }
[AttributeUsage(AttributeTargets.Property,AllowMultiple=true)]
public class EnumHelper : Attribute
{
public Type MyEnum;
public EnumHelper(Type enum)
{
MyEnum = enum;
}
}

The parameter should be an enum value, not an enum type, like:
[EnumHelper(Days.Sat)]

Just wanted to add how I ran into this and fixed it. I had my property named the same as my enumeration. The code would compile and run, but I was getting a the red line error message in the IDE. Changing the name of the property to something unique cleared the message.

Related

Map enum to json property

I have a class called InstrumentConfigValues with properties that has type implementing an interface. Now I have an enum by name InstrumentConfig which has set of values. These values are like keys inside the json file. I want to map something like [JsonProperty(InstrumentConfig.LowDiskpace.ToString()].
For some reason its not allowing this and complains saying:
An attribute argument must be constant expression
I referred to many post specifically JsonStringEnumConverter. But how can I map each property with the enum key. I also saw this post JsonSerializationSettings but not able to correlate to my problem. Please help/
public class InstrumentConfigValues : IInstrumentConfig
{
public double SpaceNeededForSingleRun
{
get; set;
}
public int NumberOfInputSlots
{
get; set;
}
public int SupportedChannelCount
{
get; set;
}
}
//I want this inheritance as some other class wants to access the values.
public abstract class InstrumentConfigReadWrite : InstrumentConfigValues
{
protected ReturnCodes PopulateValuesFromJObject(JObject jObject, string path)
{
try
{
if (JsonConvert.DeserializeObject<InstrumentConfigValues>(jObject.ToString()) == null)
{
return ReturnCodes.ErrorReadingFile;
}
}
catch (JsonSerializationException jex)
{
SystemDebugLogLogger.LogException(jex, "Invalid Instrument Config File Values. Data needs to be copied over.");
return ReturnCodes.ErrorReadingFile;
}
return ReturnCodes.Success;
}
}
As long as you're using a current compiler, you can use nameof.
[JsonProperty(nameof(InstrumentConfig.LowDiskpace))]
If you try using this, and get an error like Compilation error: The name 'nameof' does not exist in the current context, that means you're not using a current compiler. The nameof keyword was introduced in C# 6.0/Visual Studio 2015--anything newer than that should be fine.

Use enum in Entity Framework Table :what for?

Good day,
I have been learning some Entity Framework and I came to this code
public class Test
{
public int Id { get; set; }
public string name { get; set; }
public testEnum testEnum { get; set; }
}
public enum testEnum {
numero1=1,
numero2=2
}
Then I run add-migration xxxxx and update-database, the problem is that when I go to SQL server, I can not see the enum anywhere.
My questions are:
1.What happened with the enum and how can I see it in SQL server?
2. When do I use enum instead of a table like the following:
public class EnumReplace{ public int Id { get; set; }
public int value{ get; set; }
}
thank you.
1.What happened with the enum and how can I see it in SQL server?
The enum gets stored in the database table as an integer. You wouldn't be able to see the enumeration in the database. EF takes the responsibility of casting the underlying type to the enumeration defined while retrieving the values from the database.
In Entity Framework, an enumeration can have the following underlying types: Byte, Int16, Int32, Int64 , or SByte.
Read more about enum support in EF code first here
2. When do I use enum instead of a table like the following:
When we have a predefined set of values allowed for a property/field, we usually use enumeration. For e.g.
enum Days
{
Sat,
Sun,
Mon,
Tue,
Wed,
Thu,
Fri
};
You could also use Flagged Enums, Read more about enum here.
you have to have the enum in your class. something like this:
public testEnum MyProperty{ get; set; }
so basically you can't have enum as a table. you can have enum as a type of one of your properties in a table.

how to create a collection of a type that has a generic value type argument

I'm trying to create a collection (list<> or IEnumerable<>) of a custom objet "InventorAttribue" that has 2 properties; Name and Value.
The "Value" property can be of various type so I thought of coding this object like this:
public class InventorAttribute<T> {
public InventorAttribute (string name, T value) {
Name = name;
Value = value;
}
public string Name { get; set; }
public T Value { get; set; }
}
Further I plan to use an "AttiributeSet" class to represent the final Autodesk Inventor AttributeSet to be stored in an Inventor's object. Here is the class and where my question stands, because of course, this code does not work as the type 'T' cannot be found (!)
public class AttributeSet
{
public AttributeSet(string category, string name {
Name = name;
Attributes = new List<InventorAttribute<T>>();
}
public string Category { get; set; }
public string Name { get; set; }
public List<InventorAttribute<T>> Attributes { get; set; }
public void AddAttribute(string name, T value){
Attributes.Add(new InventorAttribute<T>(name,value));
}
}
Question:
How can I manage to write this code, and being able to pass the "InventorAttribute.Value" type only at run time through the "AddAttribute" method.
Thanks in advance for greatly appreciated help.
Your AttributeSet class should be also parametrized:
public class AttributeSet<T>
NOTE: you cannot store InventorAttribute<T> parametrized with different T types in Attributes collection. Even if you could do that, how would you consume such collection? You will need to cast Value for each attribute to appropriate type. You will not have any benefits of having generic class here. So create non-generic InventorAttribute which will store values in property of object type.
You're probably imagining some form of inheritance. It doesn't exist here.
An InventorAttribute<string> is not a subclass of InventorAttribute<T>. Nor is it a subclass of InventorAttribute<object> (I mention this since it's usually people's next attempt to define the collection's item type). Each constructed generic type is effectively independent1.
If applicable, you may be able to introduce a new base class:
public abstract class InventorAttribute {
public string Name { get; set; }
public InventorAttribute (string name) {
Name = name;
}
}
public class InventorAttribute<T> : InventorAttribute {
public InventorAttribute (string name, T value) : base(name) {
Value = value;
}
public T Value { get; set; }
}
And you can now declare your collection to be of non-generic type InventorAttribute. But now you cannot access the Values until you cast to the more specific type.
1So far as the type system is concerned. As an implementation detail, the system is able to cleverly JIT only a single version of each method body that is applicable for all reference types. But that doesn't have any visible impact in the type system.

Map enum to string value with Entity Framework 5 [duplicate]

We have been using EF CF for a while in our solution. Big fans! Up to this point, we've been using a hack to support enums (creating an extra field on the model; ignore the enum durring mapping; and map the extra field to the column in the db that we would have used). Traditionally we have been storing our enums as strings(varchars) in the DB (makes it nice and readable). Now with enum support in EF 5 (Beta 2) it looks like it only supports mapping enums to int columns in the DB....Can we get EF 5 to store our enums as their string representation.
Where "Type" is an enum of type DocumentType
public enum DocumentType
{
POInvoice,
NonPOInvoice,
Any
}
I tried to map it using:
public class WorkflowMap : EntityTypeConfiguration<Model.Workflow.Workflow>
{
public WorkflowMap()
{
ToTable("Workflow", "Workflow");
...
Property(wf => wf.Type).HasColumnType("varchar");
}
}
I thought was going to be the magic bullet but..
That just throws:
Schema specified is not valid. Errors: (571,12) : error 2019: Member
Mapping specified is not valid. The type
'Dodson.Data.DataAccess.EFRepositories.DocumentType[Nullable=False,DefaultValue=]'
of member 'Type' in type
'Dodson.Data.DataAccess.EFRepositories.Workflow' is not compatible
with
'SqlServer.varchar[Nullable=False,DefaultValue=,MaxLength=8000,Unicode=False,FixedLength=False]'
of member 'Type' in type 'CodeFirstDatabaseSchema.Workflow'.
Your thoughts?
This is currently not possible. Enum in EF has same limitations as enums in CLR - they are just named set of integer values. Check this article for confirmation:
The EF enum type definitions live in conceptual layer. Similarly to
CLR enums the EF enums have underlying type which is one of Edm.SByte,
Edm.Byte, Edm.Int16, Edm.Int32 or Edm.Int64 with Edm.Int32 being the
default underlying type if none has been specified.
I posted article and related suggestion about this problem. If you want to see this feature in the future please vote for the suggestion.
I hit this problem a few weeks ago. The best I could come up with is a bit hacky.
I have a Gender enum on the class Person, and I use data annotations to map the string to the database and ignore the enum.
public class Person
{
public int PersonID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
[Column("Gender")]
public string GenderString
{
get { return Gender.ToString(); }
private set { Gender = value.ParseEnum<Gender>(); }
}
[NotMapped]
public Gender Gender { get; set; }
}
And the extension method to get the correct enum from the string.
public static class StringExtensions
{
public static T ParseEnum<T>(this string value)
{
return (T)Enum.Parse(typeof(T), value, true);
}
}
See this post for full details - http://nodogmablog.bryanhogan.net/2014/11/saving-enums-as-strings-with-entity-framework/

Referring to a passed Enum's properties without knowing its type

I have a series of enums that correspond to numeric IDs used in a database, i.e. ...
public enum ResponseType1 {
Accept = 10
Reject = 11 };
public enum ResponseType2 {
Accept = 12
Reject = 13 };
public enum ResponseType3 {
Accept = 14
Reject = 15 };
A class has a 'ResponseTypeEnum' property of type Object that gets set at runtime and will be one of the various response type enums ...
MyClass.ResponseTypeEnum = ResponseType2
I know that all of the response type enums will have both an Accept and Reject value, so what I'd like to know is whether it's possible to refer to an enum's value by name without knowing its type, i.e. once I've assigned ResponseType2 to the ResponseTypeEnum property of my class is there a way of referring to the Reject value of that enum, i.e. ...
MyClass.ResponseTypeEnum.Reject
In this case the parsed value would 11, 13, or 15 depending on which enum I assigned to the ResponseTypeEnum property.
Is this possible? And, crucially, is this good practise? Any better way of achieving this?
I don't think it's a good idea.
I would create a class ResponseType with two properties Accept and Reject.
Furthermore I would create three derived classes that set those properties to the correct values:
public abstract class ResponseType
{
private readonly int _accept;
private readonly int _reject;
protected ResponseType(int accept, int reject)
{
_accept = accept;
_reject = reject;
}
public int Accept { get { return _accept; } }
public int Reject { get { return _reject; } }
}
public class ResponseType1 : ResponseType
{
public ResponseType1() : base(10, 11) { }
}
public class ResponseType2 : ResponseType
{
public ResponseType2() : base(12, 13) { }
}
public class ResponseType3 : ResponseType
{
public ResponseType3() : base(14, 15) { }
}
MyClass.ResponseTypeEnum should be renamed to MyClass.ResponseType and changed to be of type ResponseType.
Usage would now be like this:
MyClass.ResponseType = new ResponseType1();
You can use MyClass.ResponseType in a switch statement without problems:
switch(databaseValue)
{
case MyClass.ResponseType.Accept:
// accept
break;
case MyClass.ResponseType.Reject:
// reject
break;
}
Is this possible?
You could have ResponseTypeEnum as a dynamic type.
is this good practise?
I would not recommend it
Any better way of achieving this?
Yes. You can use a more explicit class structure here eg.
class Response
{
enum type;
bool accept;
}

Categories