I'm creating an enum for a field in a Class and I need one of the values to be Start-up. However, when I type this, I get an error } expected. StartUp, on the other hand, is allowed but I really need the dash to be in there..
I also have other fields with the same problem for spaces..
Does anyone know of a way that I can get the value as shown above?
Code Example:
using System;
namespace XMLConverter.Models
{
public enum SiteStatus { Hold, Planned, Proposed, Qualifying, StartUp, Open, Enrollment Complete, Closed, Stopped, Not Selected, Withdrew }
public class Site
{
public string StudyName { get; set; }
public string SiteNumber { get; set; }
public string SiteName { get; set; }
public SiteStatus SiteStatus { get; set; }
}
}
You can't. Identifiers in C# don't allow dashes since it is an operator, so that is the same for enum values.
There is no way around this. I would suggest to replace that for another sign, like an underscore (_). Depending on the use of the enum, you might have luck with your serializer. If you for example use JSON, there are possibilities to serialize and deserialize a value differently.
Enum members are just like every other identifier, and as such their names need to satisfy a set of rules. Part of these rules means that you cannot have dashes in identifier or enum names names.
And if you think about it practically, it does not make a lot of sense. Just imagine what would happen if Start and up are two variables. Since C# ignores whitespace in expressions, Start-up would mean Start - up which is a subtraction operation.
While the enum member itself needs to be a valid identifier, you can control how it is rendered to other parties. For example, you can use the DisplayAttribute to affect how it is rendered on UIs, and you can the DataMemberAttribute to affect how it is serialized.
An identifier in c# cannot contain the dash character, so you can't do this.
If you need to obtain a description for an enum value, you could use the [Description] attribute, For example:
enum TestEnum
{
[Description("Start-up")]
StartUp
}
TestEnum val = TestEnum.StartUp;
string desc = GetEnumDescription((TestEnum)val);
Where the method GetEnumDescription looks like this: (source: How to get C# Enum description from value?)
public static string GetEnumDescription(Enum value)
{
FieldInfo fi = value.GetType().GetField(value.ToString());
DescriptionAttribute[] attributes =
(DescriptionAttribute[])fi.GetCustomAttributes(
typeof(DescriptionAttribute),
false);
if (attributes != null &&
attributes.Length > 0)
return attributes[0].Description;
else
return value.ToString();
}
There is no reason to be putting "-" in the enum values.
1.If you want to display it that way to your applications users you can create an attribute and check the value of the attribute when displaying the enum value.
2.as #patric pointed out replace it with a character and check the existense of the character when displaying the value and replace it with '-'
At the first look, it's weird, but nowadays in microservices, some other languages (like GoLang) use 'dash' in the enum name, and it is okay for them, but in c# we have to add an attribute for them to handle this problem.
using System;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
public class Program
{
public static void Main()
{
var toolViewMode = ToolViewModeType.Extended;
Console.WriteLine(toolViewMode.GetEnumMemberValue());
}
}
public static class Extensions {
public static string GetEnumMemberValue<T>(this T value)
where T : struct, IConvertible
{
return typeof(T)
.GetTypeInfo()
.DeclaredMembers
.SingleOrDefault(x => x.Name == value.ToString())
?.GetCustomAttribute<EnumMemberAttribute>(false)
?.Value;
}
}
public enum ToolViewModeType
{
[EnumMember(Value = "basic-view")]
Basic,
[EnumMember(Value = "extended-view")]
Extended
}
Related
I have an enum on helper library in my solution.
For example
public enum MyEnum
{
First,
Second
}
I want to use MyEnum in a few another project. I want to decorate this enum in each project with own attribute like this:
public enum MyEnum
{
[MyAttribute(param)]
First,
[MyAttribute(param2)]
Second
}
How to decorate enum from another library with own local attribute?
You can't do what you've described - the best you can do is to create a new Enum that uses the same set of values. You will then need to cast to the "real" enum whenever you use it.
You could use T4 templates or similar to generate the attributed enum for you - it would be much safer that way as it would be very easy to map the wrong values, making for some very subtle bugs!
Linqpad Query
enum PrimaryColor
{
Red,
Blue,
Green
}
enum AttributedPrimaryColor
{
[MyAttribute]
Red = PrimaryColor.Red,
[MyAttribute]
Blue = PrimaryColor.Blue,
[MyAttribute]
Green = PrimaryColor.Green
}
static void PrintColor(PrimaryColor color)
{
Console.WriteLine(color);
}
void Main()
{
// We have to perform a cast to PrimaryColor here.
// As they both have the same base type (int in this case)
// this cast will be fine.
PrintColor((PrimaryColor)AttributedPrimaryColor.Red);
}
Attributes are compile-time additions (metadata) to code. You can not modify them when using the compiled code assembly.
(Or perhaps you could if you are a diehard low-level IL wizard, but I certainly am not...)
If your enum values require modification or parameters at various places, then you should consider other solutions, e.g. a Dictionary or even a Database Table.
E.g. using a Dictionary:
var values = new Dictionary<MyEnum, int>()
{
{ MyEnum.First, 25 },
{ MyEnum.Second, 42 }
};
var valueForSecond = values[MyEnum.Second]; // returns 42
You can do something like this, but it will be tedious.
The idea is to use your project settings to allow the change when you import the enum in a new project.
First, you will need 2 attributes:
// This one is to indicate the format of the keys in your settings
public class EnumAttribute : Attribute
{
public EnumAttribute(string key)
{
Key = key;
}
public string Key { get; }
}
// This one is to give an id to your enum field
[AttributeUsage(AttributeTargets.Field)]
public class EnumValueAttribute : Attribute
{
public EnumValueAttribute(int id)
{
Id = id;
}
public int Id { get; }
}
Then, this method:
// This method will get your attribute value from your enum value
public object GetEnumAttributeValue<TEnum>(TEnum value)
{
var enumAttribute = (EnumAttribute)typeof(TEnum)
.GetCustomAttributes(typeof(EnumAttribute), false)
.First();
var valueAttribute = (EnumValueAttribute)typeof(TEnum).GetMember(value.ToString())
.First()
.GetCustomAttributes(typeof(EnumValueAttribute), false)
.First();
return Settings.Default[String.Format(enumAttribute.Key, valueAttribute.Id)];
}
I did not check if the type is correct, not even if it finds any attributes. You will have to do it, otherwise you will get an exception if you don't provide the right type.
Now, your enum will look like that:
[Enum("Key{0}")]
public enum MyEnum
{
[EnumValue(0)] First,
[EnumValue(1)] Second
}
Finally, in your project settings, you will have to add as many lines as the number of members in your enum.
You will have to name each line with the same pattern as the parameter given to EnumAttribute. Here, it's "Key{0}", so:
Key0: Your first value
Key1: Your second value
etc...
Like this, you only have to change your settings values (NOT THE KEY) to import your enum and change your attributes to a project to another.
Usage:
/*Wherever you put your method*/.GetEnumAttributeValue(MyEnum.First);
It will return you "Your first value".
I have a program where I use a class store settings. I need it to use set and get functions to change and store settings. I have tried this, and I don't get it to work. Can anyone help me with this one?
private enum _Difficulty { Easy, Normal, Hard };
public void SetDifficulty(Difficulty)
{
_Difficulty = Difficulty;
}
public enum GetDifficulty()
{
return _Difficulty;
}
Is there no way to use enums in a class with get and set?
I also need this with bool and int.
There are several things wrong here:
Your enum is private, but your methods are public. Therefore you can't make your methods return type be the enum type, or have parameters with that type
Your SetDifficulty method has a parameter of just Difficulty - is that meant to be the parameter name or the type?
Your SetDifficulty method is trying to set the type rather than a field
Your GetDifficulty method is trying to use enum as a return type, and is then returning a type rather than a field
Basically, you seem to be confused about what your enum declaration is declaring - it's not declaring a field, it's declaring a type (and specifying what the named values of that type are).
I suspect you want:
// Try not to use nested types unless there's a clear benefit.
public enum Difficulty { Easy, Normal, Hard }
public class Foo
{
// Declares a property of *type* Difficulty, and with a *name* of Difficulty
public Difficulty Difficulty { get; set; }
}
You can use get/set methods if you really want to make your code look like Java instead of C#:
public enum Difficulty { Easy, Normal, Hard }
public class Foo
{
private Difficulty difficulty;
public void SetDifficulty(Difficulty value)
{
difficulty = value;
}
public Difficulty GetDifficulty()
{
return difficulty;
}
}
Once you specify an enum using the enum keyword, that enum acts as a type, like a class or struct would.
Here's how you'd implement a property with a custom enum:
public enum _Difficulty { Easy, Normal, Hard };
public _Difficulty Difficulty { get; set; }
You code tries to assign Difficulty a value, when in fact Difficulty is the name of the enum type. I would encourage use of getters and setters as properties instead:
public enum Difficulty { Easy, Normal, Hard };
private Difficulty _difficulty;
public Difficulty CurrentDifficulty
{
get { return _difficulty; }
set { _difficulty = value; }
}
This way you can add additional code in the setter for special conditions. To use it you simply do the following:
//set
CurrentDifficulty = Difficulty.Easy;
//get
Difficulty theDifficulty = CurrentDifficulty;
The enum you want to use needs to be public. You also need an instance of that enum to store the value you're setting, you're currently setting it to your enum's declaration. Then you want to use the same enum type for what your class stores and what you pass in.
public enum Difficulty { Easy, Normal, Hard };
public Difficulty { get; set; }
There are a number of issues here:
Your enum is private, so nothing will be able to call SetDifficulty to provide it with a value from that enum. Indeed, the compiler won't allow this.
The argument to SetDifficulty is just a type, it also needs a variable name. Also a compiler error.
You're trying to get/set the value of the enumeration itself, rather than a class-level variable of the type of the enumeration. This too won't compile.
It looks like you want to do this:
public enum Difficulty { Easy, Normal, Hard }
public Difficulty DifficultySetting { get; set; }
Note that I had to change the name of the property to DifficultySetting because it conflicts with the enum name. Yours used an underscore, which would also solve that problem. However I always found that underscores are for private members and if you want consuming code to use this enum then it would need to be public. Decorating a public member with things like underscores distracts from the semantics of the name itself. In any event, the semantics are up to your personal preference, so you can modify these names as you see fit.
I'm not sure you are using them correctly. This might help...
private enum Difficulty { Easy, Normal, Hard };
private Diffuculty theDifficulty;
public void SetDifficulty(difficulty d)
{
theDifficulty = difficulty;
}
public Difficulty GetDifficulty()
{
return theDifficulty;
}
An enum is a type not a variable. Something like this would work:
public enum Difficulty { Easy, Normal, Hard };
private Difficulty _Difficulty;
public void SetDifficulty(Difficulty difficulty )
{
_Difficulty = Difficulty;
}
public Difficulty GetDifficulty()
{
return _Difficulty;
}
or more succinctly as an Auto Property:
private Difficulty Difficulty {get; set;}
Note that the enum has to be public if you want it to be accessible from public methods.
I ahve a combo whose source is an Enum. Now , among the other values(say value1, value2
etc.) there is one item Changes(%) that will be displayed in the combo .
How to define Changes(%) in the enum?
Using C#3.0
Thanks
You can't. Enum value names have to be valid C# identifiers. You shouldn't be trying to put display names in there.
Instead, consider decorating each value with a [Description] attribute which you can fetch with reflection:
public enum ChangeType
{
[Description("Changes (%)")]
PercentageChanges,
[Description("Changes (absolute)")]
AbsoluteChanges
}
Alternatively define resources, possibly using the enum value name as the resource key. This will be better for i18n purposes, apart from anything else, although more work if you don't need your app to be internationalized.
EDIT: Here's a WayBack machine archive of an article going into more detail.
C# enumerations compile out as sealed classes, inheriting from Enum, with public static fields carrying the name of your enumeration members, thus, you're asking the compiler to name fields things like "<", ">" and "=", and that's not accepted.
Enumeration values carry the same restrictions as properties and fields when it comes to naming.
FWIW ... this article goes in-depth about the exact methodology of achieving what Jon Skeet suggests >>>> ... Pulling Enumeration Descriptions From A Resource File
I use Jon's approach (a Description attribute against the enumerations) along with the extension method shown below to make it convenient to retrieve the description:
public static class EnumExtensions
{
public static T GetAttribute<T>(this Enum enumerationValue) where T : Attribute
{
T[] attributes = GetAttributes<T>(enumerationValue);
return attributes.Length > 0 ? attributes[0] : null;
}
public static string GetDescription(this Enum enumerationValue, string descriptionIfNull = "")
{
if (enumerationValue != null)
{
DescriptionAttribute attribute = enumerationValue.GetAttribute<DescriptionAttribute>();
return attribute != null ? attribute.Description : enumerationValue.ToString();
}
return descriptionIfNull;
}
}
Example of usage:
[TestClass]
public class WhenGettingDescriptionOfAnEnum
{
private enum SampleEnum
{
First,
[Description("description")]
Second
}
[TestMethod]
public void ShouldReturnNameOfEnumIfItHasNoDescription()
{
SampleEnum.First.GetDescription().Should().Be("First");
}
[TestMethod]
public void ShouldReturnDescriptionIfThereIsOne()
{
SampleEnum.Second.GetDescription().Should().Be("description");
}
}
I'm using VS 2008, and in my property pages for the project I see that I'm targeting .Net 3.5.
Here is the error I'm getting when trying to compile:
AMSDataModels.Vehicle.VIN.get' must declare a body because it is not marked abstract, extern, or partial
And here is the code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace AMSDataModels
{
public class Vehicle
{
//NodeID for datastore persistance
public Guid NodeID { get; set; }
public string VIN { get;
set {
if (value.Length != 17) throw new ArgumentOutOfRangeException("VIN", "VIN must be 17 characters");
} }
public string Make { get; set; }
public string Model { get; set; }
}
}
If I strip the body from set so that its just:
public string VIN { get; set; }
All works, but I lose my ability to check the VIN as it is set.
Does anyone have a suggestion of how to fix this or a better way to approach the problem at hand?
I really like the shorthand notation - but verifying the legitimacy of input is important too!
If you're going to add logic in the set, you need to add it into the get as well. Notice in your set you're not actually setting a value to anything?
Add a backing field,
private string _vin;
and return that in the get.
public string VIN
{
get { return _vin; }
set
{
if (value.Length != 17)
throw new ArgumentOutOfRangeException("VIN", "VIN must be 17 characters");
else
_vin = value;
}
}
When automatic properties are used, the compiler automatically generates a backer field. When you declare your own, there's no way for it to know what field to use for the get method. So you have to declare both or none.
Incidentally, your current set method only checks for the value - it never actually assigns it to anything.
Yes, you will have to declare get implementation as well. Oh, and your set code does not do anything other than validation. You will need to provide additional implementation for that as well, assuming that you want to set the value if it passes validation.
If you need anything more than just basic get/set implementation, you will have to implement the whole property, not just the difference.
You'll have to use the good ol' backing field. The short-hand notation can't be mixed. The only extra fun is to change the access modifier on get and set, e.g. get; private set;
I am creating a network chat client in C# as a side project. In addition to simple text messages, I also have slash-prefixed commands that can be entered into the input TextBox. I used a modular approach by creating an enum that contains all the various commands, and then decorating those commands with attributes.
The attributes specify what slash-prefixed command can be entered to trigger the command, as well as any aliases to the primary command identifier and the command's usage.
Example:
public enum CommandType : byte
{
[PrimaryIdentifier("file"),
AdditionalIdentifier("f"),
CommandUsage("[<recipient>] [<filelocation>]")]
FileTransferInitiation,
[PrimaryIdentifier("accept"),
AdditionalIdentifier("a")]
AcceptFileTransfer,
// ...
}
My problem arises when I try to allow multiple aliases to the primary command. I have attempted this two ways: by allowing duplicates of the AdditionalIdentifier attribute, or by making the constructor argument in AdditionalIdentifier a params string[].
With the former, I implemented it by decorating the attribute class with AttributeUsage and setting AllowMultiple to true. While this does indeed achieve what I'm looking for, I'm feeling like it could get really noisy really fast to have several lines of aliases, in addition to the other attributes.
The latter also works, however, it generates the compiler warning CS3016, and says that that approach is not CLS-compliant. Obviously, this doesn't necessarily stop me from still using it, but I've learned to always treat warnings as errors.
My actual question is should I ignore my objections with duplicates and just go ahead and use them, or is there some other solution that could be used?
Thank you.
You could also use "params string[] aliases" in the constructor to allow a variable argument list:
[AttributeUsage(AttributeTargets.Method)]
class TestAttribute : Attribute
{
public TestAttribute(params string[] aliases)
{
allowedAliases = aliases;
}
public string[] allowedAliases { get; set; }
}
This would allow you to do:
[Test("test1", "test2", "test3")]
static void Main(string[] args)
Personally I would go with the AllowMultiple approach: I don't think the "noise" is going to be that much of a problem unless you really have truckloads of identifiers for each command. But if you don't like that and want to stay CLS-compliant, one other solution would be to provide overloaded constructors for AdditionalIdentifierAttribute:
public AdditionalIdentifierAttribute(string id) { ... }
public AdditionalIdentifierAttribute(string id1, string id2) { ... }
public AdditionalIdentifierAttribute(string id1, string id2, string id3) { ... }
The downside is that this does limit you to a predetermined number of identifiers.
That said, CLS compliance is really only a major consideration if you are building a library that others are likely to use (and specifically from other languages). If this type or the library is internal to your application, then it's reasonable to ignore CLS compliance warnings.
EDIT: Thinking further about this, you have quite a lot of attributes on those enums. You might want to consider creating an abstract Command class instead, and exposing the identifiers, usage, etc. as properties of that class; then derive concrete types of Command which return the appropriate values from those properties. This potentially also allows you to move the handling logic into those Command objects rather than switching on the enum value.
Why not have a single attribute with multiple properties? Have the property for the alias take a comma-separated list. This is the approach they take in MVC for things like the AuthorizeAttribute for Roles. Internally, the property parses the string into an array for ease of use in the attribute class, but it allows you an easy way to set up your configuration.
public class IdentifierAttribute
{
public string Name { get; set; }
public string Usage { get; set; }
private string[] aliasArray;
private string aliases;
public string Aliases
{
get { return this.aliases; }
set
{
this.aliases = value;
this.aliasArray = value.Split(',').Trim();
}
}
}
Then use it like:
public enum CommandType : byte
{
[Identifer( Name = "file", Aliases = "f", Usage = "..." )]
FileTransferType,
...
}
Yet another approach would be to have the attribute take an array of strings as a constructor parameter - that way, you get the compiler to parse the array for you (at the expense of a little more goop when applying the attribute) thus:
[Identifiers(new string[] {"Bill", "Ben", "Ted"})]
A quick 'n dirty example of implementing & using such a technique looks like this:
using System;
using System.Collections.ObjectModel;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
SomeClass.TellMeAboutYourself();
}
}
public class Identifiers : Attribute
{
private string[] names;
public Identifiers(string[] someNames)
{
names = someNames;
}
public ReadOnlyCollection<string> Names { get { return new ReadOnlyCollection<string>(names); } }
}
[Identifiers(new string[] {"Bill", "Ben", "Ted"})]
static class SomeClass
{
public static void TellMeAboutYourself()
{
Identifiers theAttribute = (Identifiers)Attribute.GetCustomAttribute(typeof(SomeClass), typeof(Identifiers));
foreach (var s in theAttribute.Names)
{
Console.WriteLine(s);
}
}
}
}