Using VS2010 and .net V4.0 I would like to achieve the following:
I already have 2 resource files in my project for 2 languages - English and Czech.
I must say Resource Management in .net is excellent, I am suprised even to get code completion when implementing a String for example:
string desc = Strings.ResourceManagerDesc
This gets the string associated with the current culture of the thread.
Now I am trying to create an Enum that can have the String portion of the Enum interpreted from the Strings resources. In the following way (This code DOES NOT WORK):
public enum DownloadStatus
{
1 = Strings.DownloadState_Complete,
2 = Strings.DownloadState_Failed,
3 = Strings.DownloadState_InProgress
}
This is a made up example, but you can see the point here. Since the above code won't work, is there a best practice way to achieve what I want?
This question is old but does not have an accepted answer and I was looking for a good way to do this.
Here's what I did, I built an extension to my Enum so that it returns a value from the Resource Manager :
public enum EventType
{
NewVersion = 1,
Accepted = 2,
Rejected = 3,
BruteForce = 4
}
public static class EventTypeExtension
{
public static string Display(this EventType type)
{
return Strings.ResourceManager.GetString("EventType_" + type);
}
}
I hope this can help someone!
Enums cannot inherit from strings. In code you do not need to be concerned with the language of the code, so your enum can simply contain the relevant states.
Looks like what you need is a utility method to convert the enum value to the relevant string representation - simply make a method for this.
EDIT: when you use an enum to switch on cases, but need further information per enumerated value, I tend to drop the enum and create a host of static references and use those in the check instead. This reference can be a class wrapping an enum value, which could then expose helpful titles or descriptions.
Enums are compiled up as part of the assembly. You're essentially assigning a method to the value of the enum isn't of a constant value - the CLR is not smart enough to work out the value at compile time, it needs to be a constant.
I'd suggest that you create a different enum for each language (forget resources) and use a helper class to return the correct one depending on the langauge-context needed.
IMO, the Enum value should be reflected to the domain and should not specific to UI (language-context).
You may want to do like this
public enum DownloadStatus
{
Complete = 1,
Failed = 2,
InProgress = 3
}
and using some EnumHelper method to get culture specific description in the UI layer
var downloadStatusString = EnumHelper.GetDescription<DownloadStatus>(DownloadStatus.Complete);
and EnumHelper class will read the culture specific string from the Resource file
public static class EnumHelper
{
public static string GetDescription<T>(T value)
where T : struct
{
if (!typeof(T).IsEnum)
{
throw new ArgumentException("value must be Enum.", "value");
}
var name = value.ToString();
string resourceKey = string.Format(CultureInfo.InvariantCulture, "{0}_{1}", typeof(T).FullName, name);
object resource = HttpContext.GetGlobalResourceObject("EnumDescriptions", resourceKey, Thread.CurrentThread.CurrentUICulture);
string description = resource as string ?? name;
return description;
}
}
Note: the resource file name is EnumDescriptions and the key must be this conversion YourNamespace.EnumType_EnumValueInString. (I'm using HttpContext to get the resource value and you might want to change it if you are not using ASP.Net.)
You can get a resource via a string, and since you can convert an enum to a string, this is quite straightforward.
enum Whatever { Ready, Set, Go }
public static string GetEnumerationString(Enum enumeration)
{
string resourceName =
string.Concat(enumeration.GetType().Name, "_", enumeration);
return ResourceManager.GetString(resourceName);
}
Now in this implementation we prefixing all enum resources with the name of the enum. In a project we did it just prevents collisions with other resources and makes them easy to find. You'd have to then ensure adding resources called Whatever_Ready, Whatever_Set and Whatever_Go.
Similarly, if you were to look at the generated code for the static member Strings as you originally wrote you'd probably see:
public static string DownloadStatus_Complete
{
return ResourceManager.GetString("DownloadStatus_Complete", Resource.Culture);
}
Related
I have some code that basically checks the list of queues a current business object has been through. These queues are kept in an array aptly named _queueNames of type IKeyMap, a custom object my company uses.
I would like to get the textual names of the queues, as I need to check for the presence of a particular keyword and handle it separately if it's hit that particular queue.
I was hoping I could just do something like this;
var queues = _queueNames.ToArray().ToString();
if (queues.Contains("Condition"))
DoSomethingElse();
but that just gives me the object type, rather than a collection of the values. Looking at the KeyMap object, looks like just a simple key/value pair, might there be another way to do this?
Edit: KeyMap class & interface:
public interface IKeyMap : IDisposable
{
string Ley {get;}
string Field {get;}
}
public class KeyMap : IKeyMap
{
string _key, field;
public KeyMap(string key, string field)
{
_key = key;
_field = field;
}
public override string ToString()
{
return string.Format("{0}_{1}", Key, Field);
}
public string Key { get {return _key; } }
public string Field { get {return _field; } }
}
I left out some overrides, such as hashing & the Dispose method since I've got to manually type this out, can't copy-paste from my remote session :(
Without knowing what the objects inside of _queueNames look like, there is no exact answer. One mistake being made here is that you are checking a single string representing an entire array. What you want to do is check every object in the array for some value, or convert it to a string and check that value.
Here is an example:
foreach (var item in array)
{
if (item.ToString().Contains("Condition"))
{
DoSomethingElse();
break;
}
}
Or the LINQ way:
if (array.Any(item => item.ToString().Contains("Condition")))
DoSomethingElse();
This specific example only works if the object can be converted into a string that is useful to parse. You could also be accessing a member or invoking a function on said object to get your string. We can't know without more information, but hopefully this points you in the right direction.
In your IKeyMap interface, let's add a Boolean.
public string IsSpecial { get; set; }
When you create the object, set the IsSpecial flag. Then read it later..
var queues = _queueNames.ToArray().ToString();
if (queues.IsSpecial)
DoSomethingElse();
This avoids searching for strings, which is something you want to avoid. What if one of the other queues accidently end up with that string? Or what if you change the special string in one place but forget to change it in another? Or what if the capitalization is different? Or what if the string ends up with a special character that you can't see in it?
And even better way would be with an enum instead of Boolean.
public HandleType QueueHandleType {get;set;}
public enum HandleType {Normal, Special, SuperSpecial}
I might be misreading this, but is there any reason you can't just store the queues by name in array of Key/Value pairs, or even a Dictionary? For example:
var queues = new Dictionary<string, object>();
// add your queues to the dictionary, with the key name being your queue name
queues.Add("Queue1", myQueue);
// etc.
At that point you have a couple of options. First, you don't need to loop through the total set of queues you have -- you can simply do this:
var specialQueue = queues[mySpecialQueueString];
// do something with it
Or you can use LINQ to get any queues whose name contains your special string:
var results = queues.Where(keyValuePair => keyValuePair.Key.Contains(mySpecialString)).ToArray();
That said, Mason has a point in that you might need to worry about string matching and the like. There are, of course, several ways to go about this. If all queues have a fixed name then I like to make a NameConstants class with a bunch of static strings and refer to members of that class. Or you can do things like making them all upper and comparing to that.
I have a case where I have several sets of numbers (register values). I want to improve readability and also to check appropriate types (only certain values make sense in certain functions).
In my particular implementation, I made them enums - so I have a set of enums now.
Now I seem to have reached the end on this approach, since I want to divide them into sets of valid enums for certain applications - so function A could for example take (a value from) enumA, enumB and enumC as input, but not enumD which is a description of different functionality.
I already looked into enums in interfaces and enum inheritance - both are dead ends, not possible in C#.
I wonder now how the solution to this problem might look like. I would like to get intellisense on the possible values and also have some type safety, so that I could not (well, at least not without maliciously casting it) feed the wrong values in.
How to achieve this?
(Possible solutions would be to simply write several functions taking several different enums - still possible but not really nice, or something like Is there a name for this pattern? (C# compile-time type-safety with "params" args of different types) - both just seems not too nice.)
One option is to scrap enums and use your own clases designed to mimic enums. It will be a bit more work for you to set them up, but once you do it will be easy enough to use, and will be able to have the functionality you've described.
public class Register
{
private int value;
internal Register(int value)
{
this.value = value;
}
public static readonly Register NonSpecialRegister = new Register(0);
public static readonly Register OtherNonSpecialRegister = new Register(1);
public static readonly SpecialRegister SpecialRegister
= SpecialRegister.SpecialRegister;
public static readonly SpecialRegister OtherSpecialRegister
= SpecialRegister.OtherSpecialRegister;
public override int GetHashCode()
{
return value.GetHashCode();
}
public override bool Equals(object obj)
{
Register other = obj as Register;
if (obj == null)
return false;
return other.value == value;
}
}
public class SpecialRegister : Register
{
internal SpecialRegister(int value) : base(value) { }
public static readonly SpecialRegister SpecialRegister = new SpecialRegister(2);
public static readonly SpecialRegister OtherSpecialRegister = new SpecialRegister(3);
}
Given this, you could have a method like:
public static void Foo(Register reg)
{
}
That could take any register, and could be called like:
Foo(Register.NonSpecialRegister);
Foo(Register.OtherSpecialRegister);
Then you could have another method such as:
public static void Bar(SpecialRegister reg)
{
}
Which wouldn't be able to accept a Register.NonSpecialRegister, but could accept a Register.OtherSpecialRegister or SpecialRegister.SpecialRegister.
Sounds like you have exhausted the capabilities of the static type system on the CLR. You can still get runtime validation by wrapping each integer with a class that validates that the value you try to store in it actually is a member of the static set.
If you have a reliable test suite or are willing to do manual testing this will at least catch the bugs instead of the bugs causing silent data corruption.
If you have multiple "sets" that you want to keep apart you can either use class inheritance or have a set of user-defined conversion operators which validate that the conversion is OK at runtime.
I don't know what specific requirements you have but maybe you can use class-based inheritance to check some properties statically. The base class would be the larger set in that case and derived classes would specialize the set of allowed values.
You have basically two options:
Option 1: Multiple enums
Create multiple enums, one for each application, and replicate the values in each enum. Then you can cast between them. For example:
enum App1
{
Data1 = AppAll.Data1,
Data2 = AppAll.Data2,
Data42 = AppAll.Data42,
}
enum App2
{
Data2 = AppAll.Data2,
Data16 = AppAll.Data16,
Data42 = AppAll.Data42,
}
enum AppAll
{
Data1 = 1,
Data2 = 2,
Data16 = 16,
Data42 = 42,
}
App1 value1 = (App1)AppAll.Data2;
App2 value2 = (App2)value1;
This will give you IntelliSense.
Option 2: Determine which are allowed
Create a method that returns a boolean on which values are allowed (this may be virtual and overridden for each application). Then you can throw an exception when the enum value is wrong.
public bool IsAllowed(AppAll value)
{
return value == AppAll.Data2
|| value == AppAll.Data16
|| value == AppAll.Data42;
}
if (!IsAllowed(value))
throw new ArgumentException("Enum value not allowed.");
This will not give you IntelliSense.
A few notes:
You cannot have inheritance for enums because under the covers enums are represented as structs (i.e. value types).
In C# you can literally cast any value to your enum type, even when it is not a member of it. For example, I can do (App1)1337 even when there is no member with value 1337.
If you want compile type checking, you are better off with distinct enums for distinct cases. If you want to have a master enum with all of your possibilities you can write a test that ensures that all of your "child" enum lists are valid subsets of the master (in terms of Int casts).
As an alternative, I would have to wonder (since no code is provided, I can only wonder) if you might not be better served with objects with methods for each enum option. Then you inherit out objects with the various methods instead of enums. (After all, it seems that you are using Enums as proxies for method signatures).
i have create a class library (DLL) with many different methods. and the return different types of data(string string[] double double[]). Therefore i have created one class i called CustomDataType for all the methods containing different data types so each method in the Library can return object of the custom class and this way be able to return multiple data types I have done it like this:
public class CustomDataType
{
public double Value;
public string Timestamp;
public string Description;
public string Unit;
// special for GetparamterInfo
public string OpcItemUrl;
public string Source;
public double Gain;
public double Offset;
public string ParameterName;
public int ParameterID;
public double[] arrayOfValue;
public string[] arrayOfTimestamp;
//
public string[] arrayOfParameterName;
public string[] arrayOfUnit;
public string[] arrayOfDescription;
public int[] arrayOfParameterID;
public string[] arrayOfItemUrl;
public string[] arrayOfSource;
public string[] arrayOfModBusRegister;
public string[] arrayOfGain;
public string[] arrayOfOffset;
}
The Library contains methods like these:
public CustomDataType GetDeviceParameters(string deviceName)
{
......................
code
getDeviceParametersObj.arrayOfParameterName;
return getDeviceParametersObj;
}
public CustomDataType GetMaxMin(string parameterName, string period, string maxMin)
{
.....................................code
getMaxMingObj.Value = (double)reader["MaxMinValue"];
getMaxMingObj.Timestamp = reader["MeasurementDateTime"].ToString();
getMaxMingObj.Unit = reader["Unit"].ToString();
getMaxMingObj.Description = reader["Description"].ToString();
return getMaxMingObj;
}
public CustomDataType GetSelectedMaxMinData(string[] parameterName, string period, string mode)
{................................code
selectedMaxMinObj.arrayOfValue = MaxMinvalueList.ToArray();
selectedMaxMinObj.arrayOfTimestamp = MaxMintimeStampList.ToArray();
selectedMaxMinObj.arrayOfDescription = MaxMindescriptionList.ToArray();
selectedMaxMinObj.arrayOfUnit = MaxMinunitList.ToArray();
return selectedMaxMinObj;
}
As illustrated thi different methods returns different data types,and it works fine for me but when i import the DLL and want to use the methods Visual studio shwos all the data types in the CustomDataType class as suggestion for all the methods even though the return different data.This is illusrtated in the picture below. As we can see from the picture with the suggestion of all the different return data the user can get confused and choose wrong return data for some of the methods. So my question is how can i improve this. so Visual studio suggest just the belonging return data type for each method.
You're taking a fundamentally wrong approach.
Make each method's return type a type which includes the appropriate data. Some methods may have the same return type as each other; for other data types there may only be a single method which returns that type.
In some cases generics may help - for example, if you have different methods which return a "minimum and maximum value", sometimes long, sometimes int, sometimes float or whatever, then you could have a MinMax<T> type.
This should have given you the hint:
and the return different types of data
Given that the methods naturally "return different types of data" why would you give them all the same return type?
But putting everything into one data type is simply not the way forward. (It's also extremely inefficient, but that's a second order concern.)
Next step: get rid of those public fields, and use properties instead. You should consider whether it would make sense for some of your types to be immutable, and where you're currently exposing arrays, expose read-only collections instead.
if you really want to use the aproach you have I might sugest using dynamics
public dynamic GetDeviceParameters(string deviceName)
{
......................
code
getDeviceParametersObj.arrayOfParameterName;
return getDeviceParametersObj;
}
You are kind of working against the type system. I think your CustomDataType class will cause more problems than it will solve.
You should either create classes for each combination you will be using, or use out parameters to be able to return more than one value from a method.
There is no way to tell Visual Studio to ignore certain properties based on which method it was returned from.
I just want don't use "Managers" for each attribute and use some enum for that.
But it seems it is impossible or I am wrong?
So I try to replace
[RequiresRole("Managers")]
with
[RequiresRole(HardCodedRoles.Managers.ToString())]
...
public enum HardCodedRoles
{
Administrators,
Managers
}
How about a class instead of an enum, making the class static to avoid somebody new:ing it ?
public static class HardCodedRoles
{
public const string Managers = "Managers";
public const string Administrators = "Administrators";
}
[RequiresRole(HardCodedRoles.Managers)]
You could also use the nameof keyword, i.e.:
[RequiresRole(nameof(HardCodedRoles.Managers))]
The reason you see the error is because ToString() is a method and thus the value cannot be calculated at compile time.
If you can use [RequiresRole(HardCodedRoles.Managers)] instead, you can perform the ToString elsewhere in your code, and this could give you the functionality you need. This will require that you change the parameter of your attribute from string to HardCodedRoles.
(I would imagine that using a const won't work, because the type of the parameter will still be string, so the input won't be restricted.)
I got a need for two extacly idential enums with diffrent names
I can do
enum DoorStatus{Open,Closed,Locked,Broken};
enum WindowStatus{Open,Closed,Locked,Broken};
and will probably be bit easier to read.
but Id rather not to duplicate code
in C++ id do
typedef Door,Window;
what is the soultion in C#?
and why have both you ask?
I got Application That Handles a Window
application that handles a Door.
I want the Window application devoloper send me data using 'WindowStatus' enum
the 'Door' guy use 'DoorStatus' enum.
I believe that user should know or care I got other devices that can be abstracted similarly.
EDIT: used
enum HatchStatus{Open,Closed,Locked,Broken};
using DoorStatus = HatchStatus;
using WndowStatus = HatchStatus;
EDIT2:
Error A using clause must precede all other elements defined in the namespace except extern alias declarations
:(
If you just want an alias, you can use a using directive:
using Enum2 = Enum1;
I suppose the question is if you have two different enums that have the exact same values - then why keep both at all?
The best solution is to pick one and refactor everything to use just one.
Update
Now that you've updated your example, I think you should consider whether an enum is actually the best solution.
public class ObjectState
{
public int ID { get; set; }
public string Description { get; set; }
}//should really be immutable
//should also implement IEquatable<ObjectState> for equality
public static readonly State_Open = new ObjectState()
{ ID = 1, Description = "Open" }
public static readonly State_Closed = new ObjectState()
{ ID = 2, Description = "Closed" }
public static class DoorStatus
{
public static readonly ObjectState Open = State_Open;
public static readonly ObjectState Closed = State_Closed;
}
//and WindowStatus if you want.
public class Door {
public ObjectState State { get; set; }
} //or perhaps refactor to a shared base/interface StatefulObject
Now you can simply do:
new Door() { State = DoorStatus.Open; }
If you also implement IEquatable<ObjectState> then you can compare the equality of two object's state as well; you'd then likely implement GetHashCode as well meaning you can also use a state as a key in a grouping or dictionary.
The good thing now is that both an open window and an open door now have exactly the same state that equate directly, rather than using some syntactic sugar to get around a design that required identical enums.
Final Update
Since the above is 'horribly complex' - despite being, I think, good design; the best you can do is ensure that two separate enums at least share the same underlying values for identical states:
public enum States
{
Open
}
public enum DoorStates
{
Open = States.Open
}
public enum WindowStates
{
Open = States.Open
}
Ultimately if you're using an enum you cannot get around the need to have two separately defined ones - this solution simply means that Open is equal for any object that can be in an Open state.