I am not sure if a constructor is exactly what I am looking for but if I explain what I am trying to do hopefully someone can tell me if I am trying to do is a silly idea or whether there are ways to do it.
So I have an enum:
public enum MessageType
{
Normal,
Error,
Chat,
Groupchat,
Headline
}
This enum is basically a wrapper for the jabber.net MessageType. So I want to create my enum from this. So at the moment I have a function like this:
private MessageType ConvertMessageType(JabberMessageType jabberType)
{
MessageType type = MessageType.Error;
switch (jabberType)
{
case JabberMessageType.normal:
type = MessageType.Normal;
break;
//etc
}
return type;
}
So I have to use enum MessageType type = ConvertMessageType(JabberMessageType.groupchat);
What I would like though is to be able to do something like:
enum MessageType type = MessageType(JabberMessageType.groupchat);
// or
enum MessageType type = MessageType.FromJabberJid(JabberMessageType.groupchat);
So that the conversion belongs with the enum rather than being a method outtside of.
Why not create an extension method to do this for you?
public static class ExtensionMethods
{
public static MessageType ConvertMessageType(this JabberMessageType jabberType)
{
switch(jabberType)
{
case JabberMessageType.normal:
return MessageType.Normal;
// Add rest of types here.
default:
return MessageType.Error;
}
}
}
Example usage:
var type = JabberMessageType.normal; // JabberMessageType
var messageType = type.ConvertMessageType(); // Converted to your custom MessageType
You can't do this. An Enumeration Type translates to an int (or byte, sbyte, short, uint, long or ulong if specified) value and is not technically a class.
An enumeration type (also named an enumeration or an enum) provides an
efficient way to define a set of named integral constants that may be
assigned to a variable.
One solution would be to put a static method to do this in a Utilities class.
MessageType type = Utilities.MessageTypeFromJabberJid(JabberMessageType.groupchat);
How about a class where your enum is nested?
Something like this
public static class Message
{
public enum Types
{
}
public static Message.Types ConvertMessageType(Message.Types jabberType)
{
}
}
You can write a simple one-liner which require less tweaking in future (in case further enum values are added), but this assumes, the enum names are the same in both types:
private MessageType ToMessageType(this JabberMessageType jabberType)
{
return Enum.Parse(typeof(MessageType), jabberType.ToString(), true);
}
This is some kind of a mapping functionality, from one type to another.
Related
Because Enums aren't guaranteed to be of type int...
public enum ExampleEnum : int / ulong / whatever
You cannot do this with enums:
int i = (int)exampleEnum;
However in my case, while I don't know the exact 'type of enum' being used, I can guarantee that it will be a "int type" of enum.
So I can do this:
int i = Convert.ToInt32(exampleEnum);
Cool. Here's the problem: I don't know of a way to do the inverse (which I need to do), as:
Enum exampleEnum = (Enum)exampleEnum;
has error:
Cannot cast expression of type 'int' to type 'Enum'
And I cannot find an inverse of Convert.ToInt32(Enum enum)
That is the question, if you think more detail on what I'm trying to do is useful, I can provide you with it. But in a nutshell I am creating a generic GUI method that takes in any type of Enum:
public static int EditorPrefEnumField(string label, Enum defaultValue, string editorPrefString)
and getting it to work (the way I want) involves converting the Enum to and from an int.
You can use Enum.ToObject() method. You need to specify the actual enum type for that. Here is a generic method to encapsulate Enum.ToObject()
public enum TestEnum : int
{
A=1, B=2, C=3
};
public T GetEnumFromInt<T>(int value) where T : Enum
{
return (T)Enum.ToObject(typeof(T), value);
}
private void button1_Click(object sender, EventArgs e)
{
Enum value = GetEnumFromInt<TestEnum>(2);
MessageBox.Show(value.ToString()); // Displays "B"
}
You need to specify the concrete type of Enum you want because Enum is an abstract type and one cannot create instances of abstract types.
Take this code where I store an error code as an Int:
public class CommonError
{
public int Code { get; set; }
public CommonError FromErrorCode(Enum code, string description = "")
{
Code = (int)Enum.Parse(code.GetType(), code.ToString());
return this;
}
}
Yet what I'm doing when I call it is parsing in different Enums:
new CommonError().FromErrorCode((int)GeneralErrorCodes.SYSTEM_BASE_ERROR);
Cool. Here's the problem: I don't know of a way to do the inverse (which I need to do)
To do the reverse of this you need the Enum Type, eg:
Enum.GetNames(typeof(AnEmumType))
Enum.GetValues(typeof(AnEmumType)).ToList();
I would like a function to give me back enum types depending on another enum's value. Here's a simplified and full of imagery example of what I would like to achieve. This leads to an "is a type but is used like a variable" error.
Is there a way to implement such function ?
Thanks a lot !
public class MyClass
{
public enum MondayActivities { ... }
public enum TuesdayActivities { ... }
public Enum PossibleActivitiesByDay(DayEnum day)
{
switch (day)
{
case DayEnum.Monday:
return MondayActivities ;
case DayEnum.Tuesday:
return TuesdayActivities ;
...
}
}
}
Yes, there is a way to do it, but you're not going to like it because the values you get back are going to be more-or-less useless! You wont know what they are.
public enum DayEnum{Monday,Tuesday}
public enum MondayActivities { Washing, Ironing }
public enum TuesdayActivities { Cleaning, Hoovering }
public static Array PossibleActivitiesByDay(DayEnum day)
{
switch (day)
{
case DayEnum.Monday:
return Enum.GetValues(typeof(MondayActivities)) ;
case DayEnum.Tuesday:
return Enum.GetValues(typeof(TuesdayActivities )) ;
}
return null;
}
Usage:
foreach(var value in PossibleActivitiesByDay(DayEnum.Monday))
{
Console.WriteLine(value);
}
Live example: http://rextester.com/CTUBYA10553
That works, as you can see, in that it prints the name of the returned values, but programatically you have no type-safety - you dont know if its a MondayActivity or a TuesdayActivity.
The answer is pretty much already in your question. Just return wanted enum's type, not value or general-purpose Enum.
public Type PossibleActivitiesByDay(DayEnum day)
{
switch (day)
{
case DayEnum.Monday:
return typeof(MondayActivities) ;
case DayEnum.Tuesday:
return typeof(TuesdayActivities) ;
...
}
}
Even if Enum is a type inside CLR, it does not support polymorphism, so you can not abstract it over some hypothetical "base" enum .
The only reasonable solution, I'm afraid, in presented case is to define distinct functions that return concrete enum types.
I have an enum like:
public enum Test:int
{
A=1,
B=2
}
So here I know my enum is an int type but if I want to do something like following:
int a = Test.A;
this doesn't work.
If I have a class like:
public class MyTest
{
public static int A =1;
}
I can say ,
int a = MyTest.A;
Here I don't need to cast A to int explicitly.
So here I know my enum is an int type
No, it's not. It has an underlying type of int, but it's a separate type. Heck, that's half the point of having enums in the first place - that you can keep the types separate.
When you want to convert between an enum value and its numeric equivalent, you cast - it's not that painful, and it keeps your code cleaner in terms of type safety. Basically it's one of those things where the rarity of it being the right thing to do makes it appropriate to make it explicit.
EDIT: One oddity that you should be aware of is that there is an implicit conversion from the constant value 0 to the enum type:
Test foo = 0;
In fact, in the MS implementation, it can be any kind of constant 0:
Test surprise = 0.0;
That's a bug, but one which it's too late to fix :)
I believe the rest for this implicit conversion was to make it simpler to check whether any bits are set in a flags enum, and other comparisons which would use "the 0 value". Personally I'm not a fan of that decision, but it's worth at least being aware of it.
"The underlying type specifies how much storage is allocated for each enumerator. However, an explicit cast is needed to convert from enum type to an integral type".
With your updated example:
public class MyTest
{
public static int A =1;
}
And usage:
int a = MyTest.A;
That's not how enums look. Enums look more like (comments are places where we differ from a real enum):
public struct MyTest /* Of course, this isn't correct, because we'll inherit from System.ValueType. An enum should inherit from System.Enum */
{
private int _value; /* Should be marked to be treated specially */
private MyTest(int value) /* Doesn't need to exist, since there's some CLR fiddling */
{
_value = value;
}
public static explicit operator int(MyTest value) /* CLR provides conversions automatically */
{
return value._value;
}
public static explicit operator MyTest(int value) /* CLR provides conversions automatically */
{
return new MyTest(value);
}
public static readonly MyTest A = new MyTest(1); /* Should be const, not readonly, but we can't do a const of a custom type in C#. Also, is magically implicitly converted without calling a constructor */
public static readonly MyTest B = new MyTest(2); /* Ditto */
}
Yes, you can easily get to the "underlying" int value, but the values of A and B are still strongly typed as being of type MyTest. This makes sure you don't accidentally use them in places where they're not appropriate.
The enum values are not of int type. int is the base type of the enum. The enums are technically ints but logically (from the perspective of the C# language) not. int (System.Int32) is the base type of all enums by default, if you don't explicitly specify another one.
You enum is of type Test. It is not int just because your enum has integers values.
You can cast your enum to get the int value:
int a = (int) Test.A;
I'm looking for a way to convert an object to one of several different types of structs. I need structs because I need it to be non-nullable. I'm not sure how to go about this, but this is what I've tried so far and it doesn't work because:
"Object must implement IConvertible." <- trying Convert.ChangeType
public class Something
{
private object[] things;
public Something()
{
//I don't know at compile time if this will
//be an array of ThingA's or ThingB's
things = new object[1];
things[0] = new ThingA();
ThingA[] thingsArrayA = GetArrayofThings<ThingA>();
things[0] = new ThingB();
ThingB[] thingsArrayB = GetArrayofThings<ThingB>();
}
public TData[] GetArrayofThings<TData>() where TData : struct
{
return (TData[])Convert.ChangeType(things, typeof(TData[]));
}
}
[Serializable]
public struct ThingA
{
//...
}
[Serializable]
public struct ThingB
{
//...
}
This is the working implementation thanks to Serg's answer:
public TData[] GetArrayofThings<TData>() where TData: struct
{
return things.OfType<TData>().ToArray<TData>();
}
I'm still curious about any penalties for .ToArray() because this is data which will be sent to a stream object, and there could be a lot of it.
It seems to me that a few LINQ queries will suffice.
//getting only ThingA from mixed array
IEnumerable<ThingA> thingsA = things.OfType<ThingsA>()
//we know type of thins inside array, so we just need type conversion
IEnumerable<ThingB> thingsB = things.Cast<ThingB>()
Don't use Convert, it's for real conversion (e.g, string to int), and what you have is type casting.
ChangeType method signature exposes two parameters, the first: value must be an object which implements IConvertible interface. In your example things is an object array and doesn't implement that interface.
You should design your GetArrayOfThings method in a different way like this:
public TData[] GetArrayofThings() where TObject:IConvertible, TData: struct
I have a C# annotation which is :
[AttributeUsage(AttributeTargets.Method)]
public class OperationInfo : System.Attribute {
public enum VisibilityType {
GLOBAL,
LOCAL,
PRIVATE
}
public VisibilityType Visibility { get; set; }
public string Title { get; set; }
public Func<List<string>, List<string>> Func;
public OperationInfo(VisibilityType visibility, string title, Func<List<string>, List<string>> function) {
Visibility = visibility;
Title = title;
Func = function;
}
}
As you can see, there is a property which is a Func and I want to call it dynamically. Basically, I'd like to parse all the methods which have this annotation and then call the Func binded to the annotation.
I'd like to use it like this (this is a simple example of an echo function, which gets a string and return the same string):
[OperationInfo(OperationInfo.VisibilityType.GLOBAL, "echo", IDoEcho)]
public static string DoEcho(string a)
{
return a;
}
[OperationInfo(OperationInfo.VisibilityType.PRIVATE, null, null)]
public static List<string> IDoEcho(List<string> param) {
return new List<string>() { DoEcho(param[0]) };
}
I've got no error in my Annotation class but when it comes to regenerate the entire solution, each time I declare a method with the annotation I've got an error which tells me that I must use literals in an annotation.
I understand there is limitations, but is there any way I can avoid this problem? I know I can use a string instead of a Func, and look dynamically for the function whose name is the same as the string, but I would like not to do so.
Thanks for helping :)
From the C# spec:
17.1.3 Attribute parameter types
The types of positional and named parameters for an attribute class are limited to the attribute parameter types, which are:
· One of the following types: bool, byte, char, double, float, int, long, sbyte, short, string, uint, ulong, ushort.
· The type object.
· The type System.Type.
· An enum type, provided it has public accessibility and the types in which it is nested (if any) also have public accessibility (§17.2).
· Single-dimensional arrays of the above types.
I don't think it is possible, c# only allows you to use Attributes with constant values only.
One way of doing this would be to create a class instead of a func, and then you pass the type of that class into the attribute.
You'd then need to instantiate it with reflection and execute a method in it.
So an example would be:
public interface IDoStuff
{
IList<string> Execute();
}
then your attribute would take a type instead of a Func
public OperationInfo(VisibilityType v, string title, Type type)
{
///...
}
you then would create a class that implements your interface and pass it into the attribute. Although this would mean that (at least initially, and without knowing your problem) you will need to create a new class every time you want to return different results.