Advice about building an error code lookup in C# - c#

I'm new to C# and so forgive me if I have some of my concepts skewed. I'm working with the Canon EDSDK, and to make life easier I'd like to be able to see error messages as text rather than hex values. The EDSDK.cs file contains a long list of errors such as :
public const uint EDS_ERR_TAKE_PICTURE_CARD_NG = 0x00008D07;
public const uint EDS_ERR_TAKE_PICTURE_CARD_PROTECT_NG = 0x00008D08;
Ideally I'd like to put all of these into some sort of lookup table so I can input a HEX errorcode and return the actual message as a string. For example
Hashtable EDSDKErrorCodes = new Hashtable();
EDSDKErrorCodes.Add("0x00008D01", "EDS_ERR_TAKE_PICTURE_AF_NG");
EDSDKErrorCodes.Add("0x00008D08", "EDS_ERR_TAKE_PICTURE_CARD_PROTECT_NG");
etc etc...
The later in my code I could grab the error message returned from one of the EDSDK methods and display it in a human readable form :
errorcode= EDSDK.EdsInitializeSDK();
MessageBox.Show(Convert.ToString(EDSDKErrorCodes[errorcode]));
My question is .. is this a good way to handle all these error codes or is there a better and more efficient way that people would recommend? If so how I could fill my hash table as a series of constants rather than having to use the Add method?

Another way you could do this is by creating an Enum with a description attribute. See here for the full details. This is summarizing how it would look:
public enum ErrorCodes : uint
{
[Description("Description for EDS_ERR_TAKE_PICTURE_CARD_NG")]
EDS_ERR_TAKE_PICTURE_CARD_NG = 0x00008D07,
[Description("Description for EDS_ERR_TAKE_PICTURE_CARD_PROTECT_NG")]
EDS_ERR_TAKE_PICTURE_CARD_PROTECT_NG = 0x00008D08
}
At the very simplest, if you didnt care about a description, you could convert the enum name to string using Enum.GetName

You could use an enum for this.
public enum ErrorCodes : uint
{
EDS_ERR_TAKE_PICTURE_CARD_NG = 0x00008D07,
EDS_ERR_TAKE_PICTURE_CARD_PROTECT_NG = 0x00008D08
}
Then your usage could be something like the following:
ErrorCodes error = (ErrorCodes)EDSDK.EdsInitializeSDK();
MessageBox.Show(Enum.GetName(typeof(ErrorCodes), error));

I would think making an enum would be superior:
public enum CanonErrorCode
{
SomeErrorDescription = 14,
SomeOtherErrorDescription = 15
// .. etc
}
You simply do the conversion from hex to integer. Then you can simply call it like so:
// Samples
var myErrorCode = (CanonErrorCode)someIntegerValue;
var myErrorCode = CanonErrorCode.SomeOtherErrorDescription;
If you want human formatted error descriptions, then I would suggest some kind of mapping like:
static Dictionary<int, string> errorlookups = new Dictionary<int, string>();
errorLookups.Add(10, "This is the human readable error message.");
errorLookups.Add(17, "Create this guy once in a static constructor.");

You could use a Generic Dictionary instead of a hashtable
Dictionary<uint, String> myDict = new Dictionary<uint, String>();
You can then retrieve the value you want by doing
MessageBox.Show(myDict[errorCode]);
For adding, I think you might be able to do something with reflection to reflect over the EDSDK class and find all the constant uint members. Then iterate through that list adding the value and the constant name.

Ok, another take since we are rolling :-)
This solution also produces a human-readable error string if the current error code is not defined.
Create an Enum like so:
public enum ErrorCode : uint
{
EDS_ERR_TAKE_PICTURE_CARD_NG = 0x00008D07,
EDS_ERR_TAKE_PICTURE_CARD_PROTECT_NG = 0x00008D08
}
Then, create an Extension Method for the enum type like this:
public static class ErrorHandler
{
public static string ToErrorString(this ErrorCode errorCode)
{
return Enum.IsDefined(typeof(ErrorCode), errorCode) ?
errorCode.ToString() : "Undefined error code";
}
}
And finally, use it like that:
var errorCode = (ErrorCode)EDSDK.EdsInitializeSDK();
MessageBox.Show(errorCode.ToErrorString());

First of all, you should use a generic dictionary instead of a hashtable. Second, I don't know anything about the Canon EDSDK, but it seems odd that it returns an error code as a hex string rather than simply a uint as the constants are defined. Is that really how they are being returned? If so, that's weird, but you should be able to convert them to an integer, otherwise, you can skip that step.
If you want to create the array using reflection, you could do something like this:
Dictionary<int,String> EDSDKErrorCodes = new Dictionary<int,String>;
System.Reflection.FieldInfo[] fields = typeof(EDSDK).GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
foreach (System.Reflection.FieldInfo field in fields) {
EDSDKErrorCodes[(uint)field.GetValue(null)] = field.Name;
}
And you can then access it using:
MessageBox.Show(EDSDKErrorCodes[errorCode]);
If errorCode is a string, convert it first using:
uint errorNumber = uint.Parse(errorCode.Substring(2), System.Globalization.NumberStyle.HexNumber);

Related

storing struct type in a list or dictionary in c#

I have existing legacy code in C# where we store struct type in a memlib type and then create 3 keys to access the memlib structs in a faster way. Please have a look at the below snapshot:
public struct gtBuildRecType : ICloneable
{
public double dParentLocCd; // 8 bytes : Key1
public double dLocationCd; // 8 bytes : Key2
public int lHierLevel; // 4 bytes : Key3
public int lSequence;
public int lDupChecked;
public int nStatusInd;
}
Memlib record and the 3 keys are defined like as following:
static public Memlib<gtBuildRecType> gnBuildTable = null;
static public Key<gtBuildRecType> gnBuildParentCdKey = null;
static public Key<gtBuildRecType> gnBuildLocCdKey = null;
static public Key<gtBuildRecType> gnBuildHierLevelKey = null;
Now, gnBuildTable Memlib can contain thousands of struct records and we can use any of the 3 keys i.e., gnBuildParentCdKey, gnBuildLocCdKey, gnBuildHierLevelKey for faster access. For example:
gtBuildRecType uTempRec = gtBuildRecType.CreateInstance();
MemLibStatus nReturn = gnBuildTable.ReadEqual(gnBuildParentCdKey, ref uTempRec);
This piece of code will immediately fill the uTempRec from gnBuildTable where the gnBuildParentCdKey matches a struct record in the gnBuildTable and then we can update the uTempRec accordingly and save the changes.
NOW, My question is: I want to replace the Memlib with List or Dictionary. I would want to store these thousands of struct records in either List or Dictionary but How shall I implement the 3 keys approach with List or Dictionary, so that my search becomes even faster????. I started with List(Not using any key) but half way across i am facing issues to search for accurate struct record in the list.
I had initially tried a dictionary approach as well using single key but i ran into issues there as well.
Thanks in advance :-)
Well, To overcome this issue I could use multi-index 3rd party library or could also work through the DataTable. Make the fields of structs as the column in datatable.

add duck-typed struct to dictionary c#

I want to add a duck-typed struct to an dictionary but i get the following error:
Argument 2: cannot convert from '[] options>' to 'UnityEngine.Object'
This is the code i have:
public class Dynamic_Interface
{
private static Dictionary<int, Object> Interface_steps = new Dictionary<int, Object>();
Dynamic_Interface()
{
var sentences = new[]
{
new
{
identifier = 1,
text = "string explain",
options = new[]
{
new
{
next = 2,
value = "this is the first option"
},
new
{
next = 2,
value = "this is the second option"
},
new
{
next = 2,
value = "this is the third option"
},
new
{
next = 2,
value = "this is the fourth option"
},
}
},
new
{
identifier = 2,
text = "string explain second var",
options = new[]
{
new
{
next = 3,
value = "this is the second first option"
},
new
{
next = 3,
value = "this is the second second option"
},
new
{
next = 3,
value = "this is the second third option"
},
new
{
next = 3,
value = "this is the second fourth option"
}
}
},
};
foreach (var sentence_obj in sentences)
{
Interface_steps.Add(sentence_obj.identifier, sentence_obj);
}
}
}
So in the end i want a dictionary containing each object in the sentences[] that has the the identifier key as name in the dictionary.
I am used to to javascript and this is really my first time doing c# so sorry for the beginner mistake. But i really cant seem to find how to get this to work.
If something is unclear let me know so i can clarify..
So, what is happening here?
When we take a closer look at the error message
Argument 2: cannot convert from '[] options>' to 'UnityEngine.Object'
it tells us that we are trying to convert the options array to the type UnityEngine.Object. Hmmm. this is weird we didn't define our Dictionary with this Unity nonsense, so why is it using that instead of C#'s Object class?!
Well you are propably using other Unity classes an probably have something like
using UnityEngine;
in your namespace. The problem with C# is that it's Object class also resides in a namespace which is called System, making it only fully identifieable by using System.Object. So if you don't have
using System;
it will happily try to use UnityEngine.Object instead of System.Object when you type Object. Thus this weird compiler error will occur.
So just use System.Object and everything is fine right?
Well Yes. But there is more to the Story!
C# also has defined aliases for it's most common types - the so called built-in types:
bool System.Boolean
byte System.Byte
sbyte System.SByte
char System.Char
decimal System.Decimal
double System.Double
float System.Single
int System.Int32
uint System.UInt32
long System.Int64
ulong System.UInt64
object System.Object
short System.Int16
ushort System.UInt16
string System.String
You will find that lowercase object is just an alias to System.Object. But wait! Doesn't that make object always use System.Object regardless of our using statements? The answer is yes, yes it does...
Let me illustrate by following example how tricky namespacing in C# can actually be:
public class Object
{
public string Name { get; set; }
}
public class TestConsole
{
public static void Main(string[] args)
{
Object fakeObject = new Object(); // -> Custom Object class
object realDeal = new object(); // -> System.Object
string name = fakeObject.Name // OK
name = realDeal.Name // NOT OK
}
}
So does that mean that we should always use the built-in alias when using System classes? Not really but we should rather use the naming convention that is used by Microsoft. That means whenever you use the class like a datatype you should use the built-in and whenever you use static members of the class you should use it's full name. For example:
object humberto = "humberto";
string rudolf = "rudolf";
Object.Equals(humberto, rudolf);
Strong typing is one of advantages of C#, its a bit more verbose than ducktyping but saves you a lot of headache, if possible try to restrain from var, its a few characters shorter but if you use strong types its much harder to accidentally ask the compiler to do something different than what you actually want:
Two options for alternative approaches that seem to immediately stand out are
class myClass { int next; string value; };
Dictionary <int, myClass> dict;
or, possibly, although I think this is not quite what you are trying to do
Dictionary<int, Dictionary<int,string>> dict;
Second option doesn't require you to declare a class type, but remember that dictionaries require unique keys. It kind of reads that you want to use array index as a key, but then you still use a dictionary, is there a reason for that? My solutions might be a bit off, but I'd be happy to suggest more if you could explain what kind of lookup you want to make.
Maybe you want to combine the above into
Dictionary<int, Dictionary<int,myClass>> dict;

Properly identifying enums with same underlying value

Assume I have this enum defined, where several members have the same underlying value:
enum Number
{
One = 1,
Eins = 1,
Uno = 1
}
According to MSDN documentation:
If multiple enumeration members have the same underlying value and you attempt to retrieve the string representation of an enumeration member's name based on its underlying value, your code should not make any assumptions about which name the method will return.
So for example,
var number = Number.One;
Console.WriteLine(number);
gives me the following output:
Eins
Printing all enum members,
Console.WriteLine($"{Number.One} {Number.Eins} {Number.Uno}");
yields the following output:
Eins Eins Eins
However, taking the nameof of each member,
Console.WriteLine($"{nameof(Number.One)} {nameof(Number.Eins)} {nameof(Number.Uno)}");
gives the following result:
One Eins Uno
So apparently the enum members are separable. Can I take advantage of this separation, i.e. is there any way I can assign a specific Number member to a variable and consistently have that same member returned whenever the variable is accessed?
So apparently the enum members are separable
Well, that's not entirely true... They are only separable at compile time.
You see, nameof is actually an expression evaluated at compile time. It is a constant expression. This can be proved by assigning a nameof expression to a const:
const string a = nameof(Number.One);
It compiles.
Trying to get the string representation of a enum value using string interpolation on the other hand, is evaluated at runtime, so this does not compile:
const string a = $"{Number.One}";
At runtime, the enum cases are not separable, so the answer to:
is there any way I can assign a specific Number member to a variable and consistently have that same member returned whenever the variable is accessed?
is "no".
The only possibility I see to always return an expected enum name is to create a 2nd enum next to your first of the underlying type and with the same values but limit the members to those that you expect (and make sure there are no shared values). Then you can cast from one to the other and use the new enum in your refactored code that relies on specific/expected members.
SomeMethod
Console.WriteLine("{0:G}", (KnownNumber)Number.Eins); // > One
Console.WriteLine("{0:G}", (KnownNumber)Number.Uno); // > One
Console.WriteLine("{0:G}", (KnownNumber)Number.One); // > One
Enums.cs
public enum Number
{
One = 1,
Eins = 1,
Uno = 1
}
public enum KnownNumber
{
One = 1,
Two = 2,
Three = 3
}
Fiddle
I wrote something that should get it work
public static class NumberExtension
{
private static Dictionary<int, string> pointers = new Dictionary<int, string>();
public static unsafe void SetValue(this Number source, string value)
{
if (pointers.ContainsKey((int)&source))
pointers[(int)&source] = value;
else
pointers.Add((int)&source, value);
}
public static unsafe string GetValue(this Number source)
{
if (pointers.ContainsKey((int)&source))
return pointers[(int)&source];
return source.ToString();
}
}
And to use:
Number num = default(Number);
num.SetValue(nameof(Number.Uno));
Console.WriteLine(num.GetValue());
However, it looks like a kind of 'hack' and I do NOT recommend it. It would be better if you look for a better solution.

Using Sprache to parse Enums from identifiers?

I am starting to use Sprache to parse a domain specific language for math expressions. I know I can parse an identifier using something like this:
static readonly Parser<string> Identifier =
from leading in Parse.WhiteSpace.Many()
from first in Parse.Letter.Once()
from rest in Parse.LetterOrDigit.Many()
from trailing in Parse.WhiteSpace.Many()
select new string(first.Concat(rest).ToArray());
From this I want to build a parser that only succeeds if the Identifier token is one of the text values of an Enum. So say I have an Enum called Dimension, with values Dimension.Location and Dimension.Time. I want to make
static readonly Parser<Dimension> DimensionIdentifier = ...
that only succeeds if what is being parsed is an Identifier and if the token string of the identifier is one of the enum names ("Location" or "Time"), and that returns the enum value, Dimension.Location or Dimension.Time respectively. Can someone help with what is probably a simple question? Thanks!
I use the following approach:
public static Parser<TEnum> ParseEnum()
{
return Enum.GetValues(typeof(TEnum))
.Cast<TEnum>()
.Select(value => Parse.IgnoreCase(Enum.GetName(typeof(TEnum), value)).Return(value))
.Aggregate((x, y) => x.Or(y));
}
It's similar to dbugger's answer, as it's still based on Parse.Or, but written in a more functional style.
Very nice solution stolen from here...
http://www.codewise-llc.com/blog/2015/8/13/parsing-enum-values-with-sprache
Build a typed helper class to build the parser for a given enum...
public static class EnumParser<T>
{
public static Parser<T> Create()
{
var names = Enum.GetNames(typeof(T));
var parser = Parse.IgnoreCase(names.First()).Token()
.Return((T)Enum.Parse(typeof(T), names.First()));
foreach (var name in names.Skip(1))
{
parser = parser.Or(Parse.IgnoreCase(name).Token().Return((T)Enum.Parse(typeof(T), name)));
}
return parser;
}
}
Then your parser is simply this...
public static Parser<Dimension> Dimension = EnumParser<Dimension>.Create();
And some unit tests (change the class name to whatever you are using, I was using the Sprache tutorial to get started)...
[Test]
[TestCase("Time", Dimension.Time)]
[TestCase("Location", Dimension.Location)]
public void ShouldGetProperEnumValue(string enumValueName, Dimension expected)
{
var eValue = QuestionnaireGrammar.Dimension.Parse(enumValueName);
Assert.AreEqual(expected, eValue);
}
[Test]
[ExpectedException]
[TestCase("Fredo")]
public void ShouldFailIfNotInList(string enumValueName)
{
var eValue = QuestionnaireGrammar.Dimension.Parse(enumValueName);
}
Interesting library, happy to learn about it.
OK, fairly easy to chain parsers...
Created a copy of your identity parser, and called it Identifier2 to keepit clear...
public static readonly Parser<string> Identifier2 =
from leading in Parse.WhiteSpace.Many()
from first in Parse.Letter.Once()
from rest in Parse.LetterOrDigit.Many()
from trailing in Parse.WhiteSpace.Many()
select new string(first.Concat(rest).ToArray());
Then added a compound parser that takes the results of the Identifier2 parser and uses the Dimension parser...
public static readonly Parser<Dimension> IdentityDimension =
from result in Identifier2
select Dimension.Parse(result);
Though not sure what you are buying -- enum parser already seems to do everything the identifier parser does.

Extending an enum via inheritance

I know this rather goes against the idea of enums, but is it possible to extend enums in C#/Java? I mean "extend" in both the sense of adding new values to an enum, but also in the OO sense of inheriting from an existing enum.
I assume it's not possible in Java, as it only got them fairly recently (Java 5?). C# seems more forgiving of people that want to do crazy things, though, so I thought it might be possible some way. Presumably it could be hacked up via reflection (not that you'd every actually use that method)?
I'm not necessarily interested in implementing any given method, it just provoked my curiosity when it occurred to me :-)
The reason you can't extend Enums is because it would lead to problems with polymorphism.
Say you have an enum MyEnum with values A, B, and C , and extend it with value D as MyExtEnum.
Suppose a method expects a myEnum value somewhere, for instance as a parameter. It should be legal to supply a MyExtEnum value, because it's a subtype, but now what are you going to do when it turns out the value is D?
To eliminate this problem, extending enums is illegal
You're going the wrong way: a subclass of an enum would have fewer entries.
In pseudocode, think:
enum Animal { Mosquito, Dog, Cat };
enum Mammal : Animal { Dog, Cat }; // (not valid C#)
Any method that can accept an Animal should be able to accept a Mammal, but not the other way around. Subclassing is for making something more specific, not more general. That's why "object" is the root of the class hierarchy. Likewise, if enums were inheritable, then a hypothetical root of the enum hierarchy would have every possible symbol.
But no, C#/Java don't allow sub-enums, AFAICT, though it would be really useful at times. It's probably because they chose to implement Enums as ints (like C) instead of interned symbols (like Lisp). (Above, what does (Animal)1 represent, and what does (Mammal)1 represent, and are they the same value?)
You could write your own enum-like class (with a different name) that provided this, though. With C# attributes it might even look kind of nice.
When built-in enums aren't enough, you can do it the old fashion way and craft your own. For example, if you wanted to add an additional property, for example, a description field, you could do it as follows:
public class Action {
public string Name {get; private set;}
public string Description {get; private set;}
private Action(string name, string description) {
Name = name;
Description = description;
}
public static Action DoIt = new Action("Do it", "This does things");
public static Action StopIt = new Action("Stop It", "This stops things");
}
You can then treat it like an enum like so:
public void ProcessAction(Action a) {
Console.WriteLine("Performing action: " + a.Name)
if (a == Action.DoIt) {
// ... and so on
}
}
The trick is to make sure that the constructor is private (or protected if you want to inherit), and that your instances are static.
Enums are supposed to represent the enumeration of all possible values, so extending rather does go against the idea.
However, what you can do in Java (and presumably C++0x) is have an interface instead of a enum class. Then put you standard values in an enum that implements the feature. Obviously you don't get to use java.util.EnumSet and the like. This is the approach taken in "more NIO features", which should be in JDK7.
public interface Result {
String name();
String toString();
}
public enum StandardResults implements Result {
TRUE, FALSE
}
public enum WTFResults implements Result {
FILE_NOT_FOUND
}
You can use .NET reflection to retrieve the labels and values from an existing enum at run-time (Enum.GetNames() and Enum.GetValues() are the two specific methods you would use) and then use code injection to create a new one with those elements plus some new ones. This seems somewhat analagous to "inheriting from an existing enum".
I didn't see anyone else mention this but the ordinal value of an enum is important. For example, with grails when you save an enum to the database it uses the ordinal value. If you could somehow extend an enum, what would be the ordinal values of your extensions? If you extended it in multiple places how could you preserve some kind of order to these ordinals? Chaos/instability in the ordinal values would be a bad thing which is probably another reason why the language designers have not touched this.
Another difficulty if you were the language designer, how can you preserve the functionality of the values() method which is supposed to return all of the enum values. What would you invoke this on and how would it gather up all of the values?
Adding enums is a fairly common thing to do if you go back to the source code and edit, any other way (inheritance or reflection, if either is possible) is likely to come back and hit you when you get an upgrade of the library and they have introduced the same enum name or the same enum value - I have seen plenty of lowlevel code where the integer number matches to the binary encoding, where you would run into problems
Ideally code referencing enums should be written as equals only (or switches), and try to be future proof by not expecting the enum set to be const
If you mean extends in the Base class sense, then in Java... no.
But you can extend an enum value to have properties and methods if that's what you mean.
For example, the following uses a Bracket enum:
class Person {
enum Bracket {
Low(0, 12000),
Middle(12000, 60000),
Upper(60000, 100000);
private final int low;
private final int high;
Brackets(int low, int high) {
this.low = low;
this.high = high;
}
public int getLow() {
return low;
}
public int getHigh() {
return high;
}
public boolean isWithin(int value) {
return value >= low && value <= high;
}
public String toString() {
return "Bracket " + low + " to " + high;
}
}
private Bracket bracket;
private String name;
public Person(String name, Bracket bracket) {
this.bracket = bracket;
this.name = name;
}
public String toString() {
return name + " in " + bracket;
}
}
Saw a post regarding this for Java a while back, check out http://www.javaspecialists.eu/archive/Issue161.html .
I would like to be able to add values to C# enumerations which are combinations of existing values. For example (this is what I want to do):
AnchorStyles is defined as
public enum AnchorStyles {
None = 0,
Top = 1,
Bottom = 2,
Left = 4,
Right = 8,
}
and I would like to add an AnchorStyles.BottomRight = Right + Bottom so instead of saying
my_ctrl.Anchor = AnchorStyles.Right | AnchorStyles.Bottom;
I can just say
my_ctrl.Anchor = AnchorStyles.BottomRight;
This doesn't cause any of the problems that have been mentioned above, so it would be nice if it was possible.
A temporary/local workaround, when you just want very local/one time usage:
enum Animals { Dog, Cat }
enum AnimalsExt { Dog = Animals.Dog, Cat= Animals.Cat, MyOther}
// BUT CAST THEM when using:
var xyz = AnimalsExt.Cat;
MethodThatNeedsAnimal( (Animals)xyz );
See all answers at: Enum "Inheritance"
You can't inherit from/extend an enum, you can use attributes to declare a description. If you're looking for an integer value, that's built-in.
Hmmm - as far as I know, this can't be done - enumerations are written at design-time and are used as a convenience to the programmer.
I'm pretty sure that when the code is compiled, the equivalent values will be substituted for the names in your enumeration, thereby removing the concept of an enumeration and (therefore) the ability to extend it.
Some time back even i wanted to do something like this and found that enum extensions would voilate lot of basic concepts... (Not just polymorphisim)
But still u might need to do if the enum is declared in external library and
Remember you should make a special caution when using this enum extensions...
public enum MyEnum { A = 1, B = 2, C = 4 }
public const MyEnum D = (MyEnum)(8);
public const MyEnum E = (MyEnum)(16);
func1{
MyEnum EnumValue = D;
switch (EnumValue){
case D: break;
case E: break;
case MyEnum.A: break;
case MyEnum.B: break;
}
}
As far as java is concerned it is not allowed because adding elements to an enum would effectively create a super class rather than a sub class.
Consider:
enum Person (JOHN SAM}
enum Student extends Person {HARVEY ROSS}
A general use case of Polymorphism would be
Person person = Student.ROSS; //not legal
which is clearly wrong.

Categories