Scenario: there is a list of string constants (over 100 now, will be more in future) which are defined like this:
public const string ChildA = "Child A";
public const string ChildASomeParameter = "Some parameter";
public const string ChildASomeOtherParameter = "Some other parameter";
...
public const string ChildB = "Child B";
public const string ChildBSomeParameter = "Some different parameter";
public const string ChildBSomeOtherParameter = "Some parameter"; // values are not unique
...
Problem: it's not pretty to use this with intellisense : when ChildA is needed you may get intellisense offering ChildASomeParameter99999 instead. Scrolling that or typing name fully is obviously not efficient.
I had idea to move parameters into nested types, like this
public const string ChildA = "Child A";
public class ChildA
{
public const string SomeParameter1 = "Some parameter 1";
public const string SomeParameter2 = "Some parameter 2";
}
But then there is a compile time issue:
The type 'MyConstants' already contains a definition for 'ChildA'
I need help (ideas) of how to deal with that issue.
My thoughts:
put ChildA into another nested type? This will add overhead: ChildA will be used more frequently than any of its parameters, using static really shine here, having to type something like Childs.ChildA is not fast.
rename something? Rename ChildA to something ugly _ChildA? Or rename nested type to something ugly? What name wouldn't be ugly then?
Maybe someone knows a better way?
How about using Current for current class?
static void Main(string[] args)
{
System.Console.WriteLine(Constants.ChildA.Current);
System.Console.WriteLine(Constants.ChildB.SomeOtherParameter);
System.Console.WriteLine(Constants.ChildA.SomeParameter);
}
public static class Constants
{
public static class ChildA
{
public const string Current = "Child A";
public const string SomeParameter = "Some parameter";
public const string SomeOtherParameter = "Some other parameter";
}
public static class ChildB
{
public const string Current = "Child B";
public const string SomeParameter = "Some different parameter";
public const string SomeOtherParameter = "Some parameter";
}
}
Use Namespaces.
Using Namespaces (C# Programming Guide)
Like this:
namespace N1 // N1
{
class C1 // N1.C1
{
class C2 // N1.C1.C2
{
}
}
namespace N2 // N1.N2
{
class C2 // N1.N2.C2
{
}
}
}
Option 1:
public class ChildA
{
public const string Name = "Child A"
public const string SomeParameter1 = "Some parameter 1";
public const string SomeParameter2 = "Some parameter 2";
}
Option 2 (with constrains):
public class ChildA
{
public const string SomeParameter1 = nameof(SomeParameter1);
public const string SomeParameter2 = nameof(SomeParameter2);
}
usage: nameof(ChildA), nameof(ChildA.SomeParameter1)
To elaborate on constraints:
cannot use arbitrary strings
nameof returns only top-level name. E.g. nameof(ChildA.ChildAA.Param1) == "Param1"
Related
I am trying to create some sort of mapping and construct a switch statement based on this.
The first thing I tried was this:
public class Class1
{
public void Test()
{
string testString_A = "A";
string testString_B = null;
switch (testString)
{
case Options.O1.aName:
testString_B = Options.O1.bName;
break;
case Options.O2.aName:
testString_B = Options.O2.bName;
break;
}
}
}
public static class Options
{
public static Option O1 = new Option()
{
aName = "A1",
bName = "B1"
};
public static Option O2 = new Option()
{
aName = "A2",
bName = "B2"
};
}
public class Option
{
public string aName;
public string bName;
}
In this scenario, compiler complains that a constant value is expected for the switch cases.
So next, I tried the following but it does not work either. The .aName I try to use in the switch statement seems not accessible.
public Class1()
{
public void Test()
{
string testString = "A1";
switch (testString)
{
case Options.O1.aName:
...
}
}
}
public static class Options
{
public static Option_O1 O1 = new Option_O1();
public static Option_O2 O2 = new Option_O2();
}
public class Option_O1
{
public const string aName = "A1";
public const string bName = "B1";
}
public class Option_O2
{
public const string aName = "A2";
public const string bName = "B2";
}
How can I accomplish what I want?
There's a big difference between a string property / field variable (even if it is static or readonly), and a const string. The switch statement requires either literals, or const values in the case statements.
This explains why your first attempt didn't succeed (Error : "A Constant value is required").
In the second case, although you could obviously do this:
switch (testString)
{
case Option_O1.aName:
return Option_O1.bName;
case Option_O2.aName:
return Option_O2.bName;
}
but as soon as you try and 'cheat' the constant switch requirement by introducing the static class container, you're back to the same problem, although a more cryptic compiler error:
case Options.O1.aName: // Cannot be accessed by an instance reference
return Option_O1.bName;
Alternative to switch
I'm guessing here, but it seems that you need to build a run time mapping function.
Assuming that you always want to return the same data type (a string), I would suggest using a Dictionary keyed by the string you are trying to 'switch' on - this mapping can be built up at run time.
Here's an example of a statically bootstrapped map:
public static class Options
{
public static Option O1 = new Option()
{
aName = "A1",
bName = "B1"
};
public static Option O2 = new Option()
{
aName = "A2",
bName = "B2"
};
}
private static IDictionary<string, Option> myOptionMap = new []
{
Options.O1, Options.O2
}
.ToDictionary(x => x.aName);
Which you can use like so:
public string Test(string someAName)
{
if (myOptionMap.TryGetValue(someAName, out var myOption))
{
return myOption.bName;
}
// Oops not found
return string.Empty;
}
Unless there's more to this than your MVP, it's unlikely that you'll want to subclass your options per instance - Option_O1
Assume we want to define a class that contains all constants that we will use in our solution. And this class doesn't have any methods.
public class _const
{
/// Group1: 'DataBase'. We naming "db" group
public const Server_Name = 'ServerName';
public const DB_Name = 'DBName';
public const DB_User = 'UserName';
public const DB_Password = 'Password';
/// Group2: 'Default Variable'. We naming "default" group
public const Title= 'DefaultTitle';
public const KeyWord = 'DefaultKeyWord';
/// Group3: 'Status' constans.We naming "status" group
public const Approved = 'Approved';
public const Rejected = 'Rejected';
public const Suspended = 'Suspended';
/// And so on...
/// ...
/// ...
/// ...
}
We know, these constants will be used anywhere in the solution simply with below instruction. And don't need to create an instance of the class.
/// For example:
string x = _const.Approved;
My question is: for easier use and more code readability, is there any way for grouping related constant together? And access to each group with own prefix name (like namespace)?
Something similar to the following code.
/// For example:
string x = _const.db.DB_Name;
string y = _const.default.KeyWord;
string z = _const.status.Approved;
I think a mix of Enum and Dictionary could help you since, though with a little more verbose call, it assures consistency throughout your code:
public enum Db
{
Server_Name,
DB_Name,
DB_User,
DB_Password,
}
public enum Default
{
Title,
Keyword
}
public enum Status
{
Approved,
Rejected,
Suspened
}
public static class _const
{
public static Dictionary<Db, string> db = new Dictionary<Db, string>()
{
{Db.Server_Name, "ServerName"},
{Db.DB_Name, "DBName"},
{Db.DB_User, "UserName"},
{Db.DB_Password, "Password"}
};
public static Dictionary<Default, string> defaults = new Dictionary<Default, string>()
{
{Default.Title, "DefaultTitle"},
{Default.Keyword, "DefaultKeyWord"}
};
public static Dictionary<Status, string> status = new Dictionary<Status, string>()
{
{Status.Approved, "Approved"},
{Status.Rejected, "Rejected"},
{Status.Suspened, "Suspended"}
};
}
that you can use in your code like:
string string_x = _const.db[Db.Server_Name];
string string_y = _const.defaults[Default.Keyword];
string string_z = _const.status[Status.Suspened];
You can make your class static and define another nested static class like this:
public static class Constants
{
public static class Group1
{
internal const string String1 = "String1";
}
}
internal class Program
{
internal static void Main()
{
Console.WriteLine(Constants.Group1.String1);
}
}
I created a new class called DashObject, then immediately created an example DashObject. But when I try to access it, the IDE says it doesn't exist.
I'm trying to manage Amazon Dash devices using this class, but I can't even access them once defined for some reason.
class DashObject
{
// Definitions
string DashName;
string DashIdentifier;
int DashFunction;
string DashFunctionInfo;
// Constructor
public DashObject(string dashName, string dashIdentifier, int dashFunction, string dashFunctionInfo)
{
DashName = dashName;
DashIdentifier = dashIdentifier;
DashFunction = dashFunction;
DashFunctionInfo = dashFunctionInfo;
}
}
//Create example DashObject
DashObject example = new DashObject("Example", "44650DFD85E9", 1, "prsl");
//Attempt to access example (this line causes build to fail)
MessageBox.Show(example.DashName);
Make sure you have a public or internal access modifier on it. Change your code to:
public class DashObject
{
// Definitions
public string DashName;
public string DashIdentifier;
public int DashFunction;
public string DashFunctionInfo;
// Constructor
public DashObject(string dashName, string dashIdentifier, int dashFunction, string dashFunctionInfo)
{
DashName = dashName;
DashIdentifier = dashIdentifier;
DashFunction = dashFunction;
DashFunctionInfo = dashFunctionInfo;
}
}
in order to access the field you must set it to public or internal:
public string DashName;
or
internal string DashName;
I am making an "error code to String" converter that would display the name of an error code from its value, for example 0x000000c3 would give "Class not found", but using MY OWN error codes!
Here's how it actually looks like:
#region errcodes
public int NORMAL_STOP = 0x00000000;
public int LIB_BROKEN = 0x000000a1;
public int RESOURCE_MISSING = 0x000000a2;
public int METHOD_NOT_FOUND = 0x000000a3;
public int FRAMEWORK_ERROR = 0x000000b1;
public int UNKNOWN = 0x000000ff;
#endregion
public string getName(int CODE)
{
}
I would like to get a string value from parameter CODE, in function getName.
How can I do that ?
A good C# practice is using of an enum:
public enum ErrorCode
{
NORMAL_STOP = 0x00000000,
LIB_BROKEN = 0x000000a1,
RESOURCE_MISSING = 0x000000a2,
METHOD_NOT_FOUND = 0x000000a3,
FRAMEWORK_ERROR = 0x000000b1,
UNKNOWN = 0x000000ff
}
public const string InvalidErrorCodeMessage = "Class not found";
public static string GetName(ErrorCode code)
{
var isExist = Enum.IsDefined(typeof(ErrorCode), code);
return isExist ? code.ToString() : InvalidErrorCodeMessage;
}
public static string GetName(int code)
{
return GetName((ErrorCode)code);
}
Another good advice: it would be great to use the C# naming convention for error codes:
public enum ErrorCode
{
NormalStop = 0x00000000,
LibBroken = 0x000000a1,
ResourceMissing = 0x000000a2,
MethodNotFound = 0x000000a3,
FrameworkError = 0x000000b1,
Unknown = 0x000000ff
}
Usage example:
void Main()
{
Console.WriteLine(GetName(0)); // NormalStop
Console.WriteLine(GetName(1)); // Class not found
Console.WriteLine(GetName(ErrorCode.Unknown)); // Unknown
}
I am trying to have the Description of an enum pulled from the resx file, but I get the above error.
Here is my code:
public enum FinalStatus
{
[Description(StringResources.MyStrings.Status_0)]
Error = 0,
[Description(StringResources.MyStrings.Status_1)]
Ok = 1,
[Description(StringResources.MyStrings.Status_5)]
Warning = 2,
[Description(StringResources.MyStrings.Status_4)]
Unknown = 3
}
The error is correct; these values need to be constants. You'll need to change your Status_n definitions to something more like this:
namespace StringResources{
public class MyStrings{
public const string Status_0 = "0";
public const string Status_1 = "1";
public const string Status_4 = "4";
public const string Status_5 = "5";
}
}