How to use a 'hard-coded' dictionary/enum - c#

I am wanting to create a 'dictionary' of strings, however I have only ever learned how to use strings to reference what I want in a dictionary. I want something with more auto-correct (as typos can happen in a large table of strings), which is why I want to know how to hard-code. (The value of the strings will be retrieved from a text file, like JSON).
I notice that Microsoft uses some type of hard-coding in their String Resource File.
So instead of doing:
string result = strings["Hello"];
I wish to do this:
string result = strings.Hello;
The only thing I can think of is to use some external tool that creates an enum/struct script with the values from the text file. Is there a better option, perhaps one built into .NET?
Edit: I think 'strongly-typed' would be a better description over 'hard-coded'.
Edit 2: Thanks for all the comments and answers. By the looks of it, some code-gen is required to fufil this result. I wonder if there's already any tools out there that do this for you (I tried looking but my terminology may be lacking). It doesn't seem too difficult to create this tool.

There are compiletime constants and runtime constants.
Your wish for Autocrrection/Intellisense support requires a compile time constants. Those are the only ones Intellisence, Syntax Highlighting and the Compiler double check for you.
But your requriement of having the values generated from a 3rd party textfile, indicates either a runtime constant or some automatic code generation. Runtime constants would take away the Editor support. While Code generation would run into issue with the Editor only having a old copy of the file. And a high risk of breaking tons of code if a string in that one file changes.
So your two requirements are inherently at odds. You need to have your cake and eat it too.
Perhaps my primitve solution to the Enum/ToString() problem might help you?
Enumeration are for most parts groups of constants, and integer ones by default. With added type checks on assignments. That makes them a good way around Primitive Obsession. You reference a value from the group like you would any constant, readonly static field or readonly property. (There is other advantages like Flags, but I doubt they mater here).
While Enums have a string you could use for display and input parsing - the one you use in sourcecode - that one is absolutely not suited for display. By default they are all-caps and you would need to support Localisation down the line. My primitive Solution was a translation layer. I add a Dictionary<someEnum, String> SomeEnumStringRepresentation. This dictionary can be generated and even changed at runtime:
I need to display any specific value, it is SomeEnumLocalisation[someEnum]. I could add a default behavior to just ToString() the compiler representation of the Enum.
I need to parse a user input? Itterate over the values until you find a match, if not throw a ParseException.
I get to use compile time checks. Without having to deal with the very inmutable compile side strings anywhere else. Or with my code side strings changing all the time.

i am not quit understand what out put you want , bu I am just throwing an idea to here - how about to extend the class string and add your own methods to it ? so when you use strings.Hello it will return what you wanted?
example :
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods

Related

Why should I declare a method parameter using a base type?

I have declared a simple method to try converting input from a text box into an int like so:
int TryConvertTextToInt(TextBox box)
{
//do try catch
}
My IDE (SharpDevelop) tries to give me some refactoring advice; specifically, that the box parameter could be declared as a base type (the two options the tool gives me are TextBoxBase and Control). I know I won't want to use this method with anything other than a TextBox, and if I do change my mind down the road, the parameter type being specific will remind me that the method may need to be changed slightly to accommodate a wider range of inputs. I don't see the value in changing the type right now, since I don't anticipate the latter case and the project is a small one.
Is there a reason I would want to do this that I'm missing, or is the IDE just being overly helpful?
In your particular case, it probably doesn't make too much of a difference. Given that you're passing a TextBox, you probably won't ever want to pass anything other than a TextBox.
However, speaking in the more generalized case, it is often best practice to have the most basic parameter types and the most specific return types possible for methods. The idea is, as your IDE suggests, to allow for use of the method in a variety of places later down the road.
As an example, we can look at the classic case of a collection. Many developers will write code that accepts a List<T> as a parameter, then do a foreach through that. That's great, if they only ever deal with List<T>, but if they then want to, down the road, expand out to incorporate some LINQ expressions in there, suddenly they're dealing with an IEnumerable<T>. Nothing in that foreach loop would require a List<T>, but because they didn't bother to use the base class (or interface in this case, which is often better), they'd now either have to change the method signature--a non-breaking change but still never a nice one to have to make--or add a .ToList() to their LINQ, which disrupts many of the advantages to using LINQ (since suddenly they have to loop through the collection probably at least three times).
You always want to make sure you're accepting the minimal class or interface you can, that still provides the members that you are going to need. Of course, don't be too conservative: if there's a right way and a generalized way, choose the right way, but if those are the same, generalized is best.
But again, in your case, I don't think it's much of a big deal. The chances are likely higher that you'll want to use other members that TextBox provides, than that you'd want to pass other inheritors of TextBoxBase or Control to your method. Really, it's all just dependent on your application. Review what you have and what you need, then build your response to this warning off of that. To me, it sounds like you're rightfully happy leaving it, and that's what you should do. But for future reference, this is the idea.
the parameter type being specific will remind me that the method may
need to be changed slightly to accommodate a wider range of inputs
But it wouldn't need to be changed to accommodate a wider range of inputs, so this "reminder" would be misleading. Your IDE has detected that it already can accommodate them because you haven't done anything TextBox-specific in your implementation. Only if you plan to make it actually TextBox-specific in the future should you ignore the advice.

Globally set String.Compare/ CompareInfo.Compare to Ordinal

I'm searching for a strategy with which I can set the default sortorder of String.CompareTo to bytewise - ordinal. I need to do this without having to specify the sortorder in the call to the method.
I have tried out several strategies without satisfactory results. I got as far as this:
CultureAndRegionInfoBuilder crib =
new CultureAndRegionInfoBuilder("foo", CultureAndRegionModifiers.Neutral);
CompareInfo compareInfo = new CustomCompareInfo();
crib.Register();
In this CustomCompareInfo I try to override the default CompareInfo class, but unfortunately this does not compile:
The type 'System.Globalization.CompareInfo' has no constructors defined
I'm stuck here. Got the feeling that a custom implementation of CompareInfo is the solution to my problem.
Got any ideas on this?
Edit: context of my question:
This project I'm working on is quite unusual - a huge codebase has been converted from an other programming language to .NET. In this programming language the string comparison defaults to ordinal and this difference with .NET is causing bugs in the converted codebase, so I figured it would be the most elegant solution if we'd be able to configure .NET to the same default behavior.
Of course it is possible to reconvert the code using a comparison-specifier. Or, we could introduce an extension method which performs a ordinal (binary) comparison. Et cetera..
However, as far as I am concerned, from an architectural viewpoint, these solutions are less elegant. This is the reason why I am searching for a solution with which I can set this ordinal comparison globally on the framework.
Thanks in advance!
Sorry, you can't make this work. The CompareInfo class does have a constructor. But it is internal and takes a CultureInfo as an argument. The actual implementation involves private members of CultureInfo that reflect sorting tables built into mscorlib. They are not extensible.
This does actually work in VB.NET, presumably the reason you are pursuing this. It has an Option Compare statement that lets you select binary comparison. This is however not implemented with CultureInfo, it is done by the compiler. Which recognizes a string comparison and replaces it with a custom vb.net string comparison method that is aware of the selected Option Compare. It's name is Microsoft.VisualBasic.CompilerServices.Operators.CompareString()
You cannot coax the C# compiler into the same behavior. You'd have to painstakingly replace comparison expressions in converted vb.net code. A horrible job of course and very prone to mistakes. If the conversion was done by a converter program then you might be better off with a good decompiler, it won't hide the CompareString() calls.
There appears to be no means of setting the default comparison mode (here, to ordinal).
If what you want is always-consistent comparison results, you can set, for each thread you create in your app, the culture to 'invariant' (cultureInfo with empty string as parameter)
Thread.CurrentThread.CurrentCulture = new CultureInfo("");
If you want to perform ordinal comparisons for performance, I really think that nothing can be done globally - you will need to pass this option explicitly each time you perform a string comparison.
Can you tell us what you need exactly?

Is there any harm in having many enum values? (many >= 1000)

I have a large list of error messages that my biz code can return based on what's entered. The list may end up with more than a thousand.
I'd like to just enum these all out, using the [Description("")] attribute to record the friendly message.
Something like:
public enum ErrorMessage
{
[Description("A first name is required for users.")]
User_FirstName_Required = 1,
[Description("The first name is too long. It cannot exceed 32 characters.")]
User_FirstName_Length = 2,
...
}
I know enums are primitive types, integers specifically. There shouldn't be any problem with that many integers, right?
Is there something I'm not thinking of? It seems like this should be okay, but I figured I should ask the community before spending the time to do it this way.
Does .Net care about enum types differently when they have lots of values?
Update
The reason I didn't want to use Resources is because
a) I need to be able to reference each unique error message with an integer value. The biz layer services an API, in addition to other things, and a list of integer values has to be returned denoting the errors. I don't believe Resources allows you to address a resource value with an integer. Am I wrong?
b) There are no localization requirements.
I think a design that has 1,000+ values in an enum needs some more thought. Sounds like a "God Enum" anti-pattern will have to be invented for this case.
The main downside I'd point out with having the friendly description in an Attribute is that this will cause challenges if you ever need to localize your app for another language. If this is a consideration, it would be a good idea to put the strings in a resource file.
The enum itself should not be a problem, though having all of your error codes in one master list can be confusing. You may consider creating seperate enums for seperate categories of return codes, as this will make it easier for developers to understand the possible return values for a particular function. You can still give them distinct numeric values (by specifying the numeric values explicitly) if it's important that the codes be unique.
On a side note, the .NET BCL does not make much use of return codes and return codes are somewhat discouraged in modern .NET development. They create maintainability issues (you can almost never remove old return codes or risk breaking backwards compatibility) and they require special validation logic to handle the returns for every call. Stateful validation can be accomplished with IDataErrorInfo, where you use an intermediate class that can represent invalid states, but that only allows a Commit of changes that are validated. This allows you to manipulate the object freely, but also provide feedback to the user as to the validity of its state. The equivalent logic with error codes often requires a switch statement for each use.
1000 is not many, you should just make sure that the underlying integer type is big enough (don't use a char for your enum.
On second thought 1000 is tons if you're manually entering them, if they are generated from some data set it could make sense kinda...
I fully agree with duffymo. An enum with 1000+ values smells bad from y design point of view. Not to mention that it would be quite nasty for the developer to use intelligence on such a GOD ENUM:-)
I would better go for using resources.
I think it's very bad, for error handling you can simply use resource, as i see you want to do reflection and fetch the description its bad too.
If you don't want to use resources, you can define different enum for each of your business rules, Also your different business doesn't need others error message (and shouldn't be like this).

string vs System.String, int vs System.Int32 : another Alias vs Type Name question

Quite often I see source code where language's keyword are replaced with full type names:
System.String, System.Int32, System.GUID etc.
Moreover, people who do this write complete type names everywhere, making source full of such declarations:
System.Collections.Generic.List<System.Reflection.PropertyInfo> list = System.Collections.Generic.List<System.Reflection.PropertyInfo>(newSystem.Reflection.PropertyInfo[] { ... });
When I ask them why do they do this, i get wide range of answers: "It helps me avoid type names collisions", "It looks more professional", "my VS plugin does it for me automatically" etc.
I understand, sometimes writing full type names helps you avoid writing unnecessary using if you use the type one time throughout the source code file. And sometimes you need to declare a type explicitly, a great example is Threading Timer and WinForms Timer.
But if you source full of DB calls and you still write System.Data.SqlClient.SqlCommand instead of 'SqlCommand' it looks quite a bit strange for me.
What do you think? Am i right or i just don't understand something?
Thank you!
P.S. And another phenomena is writing if (0 != variable) instead of if (variable != 0).
The if (0 == variable) thing is a C++ convention used to protect against accidentally writing if (variable = 0), which is valid in C++ however doesn't do what's intended. Its completely unnecessary in C# as the wrong version doesn't compile, so you should use the other version instead as it reads better.
Personally I like to write as little as possible, so unless there is a namespace clash I never fully qualify things.
As for string vs String, I always use the alias (string / int) rather than the full class name, however its purely a convention - there is no runtime difference.
I'd argue strongly against "it looks more professional", as frankly it looks the opposite to me.
That said, if I was to use a single member of a namespace in the entire source file, I might use the full name there rather than have a using.
Favouring 0 != x over x != 0 etc. does have some advantages depending on overrides of equals and a few other things. This is more commonly so in some other languages, so can be a hangover from that. It's particularly common to see people favour putting the null first, as that way it's less likely to be turned into passing null to an equality override (again, more commonly a real issue in other languages). It can also avoid accidental assignment due to a typo, though yet again this is rarely an issue in C# (unless the type you are using is bool).
It is a bit subjective but unless your coding standard says otherwise I think removing the namespace is always better as it is less vebose and makes for easier reading. If there is a namespace collision, use a shorter alias that means something.
As to your last point, if you compare name.Equals("Paul") vs "Paul".Equals(name). They both do the same thing unless name is null. In this case, the first fails with a null exception, whilst the 2nd (correctly?) returns false.
For primitive data types: Duplicate questions here - C#, int or Int32? Should I care?
For non-primitive data types: The answers given are valid, especially "It helps to avoid type names collisions"
For if (0 != variable): variable is the subject to compare in the expression, it should go first. So, I would prefer if (variable != 0).
I don't find any of these reasons convincing. Add using statements is better.
Two minor exceptions:
In generated code, you may see redundant namespace prefixes, but that is OK as this code is not indented to edited.
Sometimes it is helpful to write Int32 explicitly when depend on the type being exactly 32 bits.
Make code as readable as possible! See also: http://en.wikipedia.org/wiki/KISS_principle
"It looks professional" is a very bad argument.
BTW, if your code is full of SQL statements, then you may want to refactor that anyway.
About string vs String. I try to use string, when it is that, i.e. a string of characters as in any programming language. But when it is an object (or I am referring to the String class), I try to use String.

Auto-generate variable *name* to match parameter you're providing?

R# 4.5 (answers to 5 are welcome)
VS2008 (answers to VS2010 are welcome)
C# (FWIW)
I'm using a constructor (the question applies for methods, too), and there's Intellisense:
I don't yet have a value to specify for this first parameter, "firstName". Today, I type "firstName", then let the IDE create that variable for me (which I initialize to some value).
I understand that the IDE will create the variable for me. I want it to create the variable name for me.
I don't want to have to type "firstName". I like the variable name the parameter author chose, and I want to use that variable name in my (calling) code.
Is there a way to have these acceptable variable names re-generated for me (the calling code) automatically as I move, parameter by parameter, through this line of (calling) code?
You may get close to what you are looking for with VS2010.
Type p.Foo(
This will open the description of the currently selected constructor, out of the list of all constructors. If you type a letter, or hit ctrl + space, intellisense auto completion will open.
A difference here between VS2008 and VS2010 is named parameters. In VS2010, your completion list will have entries for the named parameters firstName: and lastName:.
Type the first letter of the parameter name (what you are referring to as "the variable name the parameter author chose")
Intellisense should jump straight to that entry, and allow you to do completion the same way it usually does.
Type a space, enter, or comma
Intellisense it will insert the identifier used for the named parameter. It won't insert the colon (unless you type it), so you don't have to use the named parameter feature to accomplish your goal here. You can just take advantage of the fact that the text you are looking for is in your completion list.
How you get Visual Studio to actually generate the local variables (which, according to your question, it seems like you have already solved) baffles me, and would be up to you to take care of :) If you've got that second problem licked, I'd like to know how, too.
You can make a code snippet that creates the variable and inserts it as parameters.
MSDN Reference on snippets
I don't understand your scenario entirely but I'm assuming you want to inject a variable name from calling assembly into the called code. if so, you may want to look into System.CodeDom that lets you create class and its memebers during runtime beside plethora of other functionality it offers.
I am pretty sure you can do it with Resharper or CodeRush/Refactor.
It sounds like to me that what your trying to do is get out of typing at all! To have the IDE put the code in you intend so you don't have to. A quite lofty goal - with the exception that you'd put us all out of work ;-(
All fun aside, what you're probably reaching for is a code gen tool such as the T4 Toolbox ( one of my new favorite toys). If you're looking for a tool that will auto-generate your code snippets as you type, that's a tall order. The nearest thing available would be Resharper.
Here is an example of a class constructor I generated from my customization of T4 Toolbox templates:
public partial class EvaluationController : SmartController
{
private readonly IEvaluationService _evaluationSvc;
private readonly IEvaluationMapper _evaluationMapper;
private readonly IEvaluationCriterionMapper _evaluationCriterionMapper;
private readonly IParticipantEvaluationMapper _participantEvaluationMapper;
public EvaluationController( IEvaluationRepository repository, IEvaluationService evaluationSvc, IEvaluationMapper evaluationMapper, IEvaluationCriterionMapper evaluationCriterion, IParticipantEvaluationMapper participantEvaluation)
{// : base(repository, evaluationMapper)
_evaluationSvc = evaluationSvc;
_evaluationMapper = evaluationMapper;
_evaluationCriterionMapper = evaluationCriterion;
_participantEvaluationMapper = participantEvaluation;
}
If that is what you're after, the place to start would be: http://t4toolbox.codeplex.com/
I've got an example project where I use customizations of the templates to spin up my business classes, various methods & repository layer.http://t4tarantino.codeplex.com/
There's an example of the level of complexity of output you can generate at
http://geekswithblogs.net/JamesFleming/archive/2010/08/18/code-generation-with-t4-toolbox.aspx
HTH

Categories