This code is not valid:
private void Foo(string optionalString = string.Empty)
{
// do foo.
}
But this code is:
private void Foo(string optionalString = "")
{
// do foo.
}
Why? Because string.Empty is a readonly field, not a constant, and defaults for optional parameters must be a compile-time constant.
So, onto my question... (well, concern)
This is what i've had to do:
private const string emptyString = "";
private void Foo(string optionalString = emptyString)
{
// do foo.
if (!string.IsNullOrEmpty(optionalString))
// etc
}
How do you guys handle optional string parameters?
Why can they not make String.Empty a compile-time constant?
Ummm... what's wrong with string optionalParm = "" again? Why is that bad? Do you really think you need a symbolic constant for an empty string in this case? How about this then?
const int Zero = 0;
void SomeMethod(int optional = Zero) { }
Does that seem at all silly to you?
if you don't like "" value you can use default(string).
I played with it and it is allowed.
private static void foo(string param = default(string)) {
if (!string.IsNullOrEmpty(param)) // or param != default(string)
Console.WriteLine(param);
}
Code Analysis warning 1026 says not to use optional parameters. It's better style to use overload methods, like this:
private void Foo()
{
Foo(string.Empty);
}
private void Foo(string optionalString)
{
// do foo.
if (!string.IsNullOrEmpty(optionalString))
// etc
}
The best way to handle them is with:
private void Foo(string optionalString = "")
{
// do foo.
}
So you can't use String.Empty. Everyone recognizes "", but if I found optionalString = nullString I wouldn't be sure what to think. If nothing else, name the thing emptyString--it's not null!
I'm answering this question.
Why can they not make String.Empty a compile-time constant?
Here is the disassemble code via Reflector of String.cs in mscorlib.dll
public static readonly Empty;
static String()
{
Empty = "";
WhitespaceChars = new char[] {
'\t', '\n', '\v', '\f', '\r', ' ', '\x0085', '\x00a0', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
' ', ' ', ' ', ' ', '', '\u2028', '\u2029', ' ', ''
};
}
So in windows platform, string.Empty is exactly "". But do you know, Martian have a different definition for Empty and WhitespaceChars in their OS.
If you are willing to play lose and treat null, "", and whitespace characters to be the same, then you can default to null. This becomes very handy when user name and password are optional fields due to a possibility of trusted connection to a db. You could change this logic to reset strings to null and thus modify the assert and the if. The important part is having a consistent convention.
private void RunSql(string serverName, string databaseName, string userName = null, string password = null)
{
userName = Strip(userName);
password = Strip(password);
// The `MsTest` assert - works in both `Debug` and `Release` modes.
Assert.AreEqual<bool>(
userName == String.Empty,
password == String.Empty,
"User name and password should be either both empty or both non-empty!");
Assert.IsFalse(String.IsNullOrWhiteSpace(serverName));
Assert.IsFalse(String.IsNullOrWhiteSpace(databaseName));
var cmdBuilder = new StringBuilder();
cmdBuilder.AppendFormat("sqlcmd -E -S {0} -d {1} ", serverName, databaseName);
if (userName.Length > 0)
{
cmdBuilder.AppendFormat("-U {0} -P {1} ", userName, password);
}
// Complete the command string.
// Run the executable.
}
// Cannot think of a good name. Emptify? MakeNullIfEmpty?
private string Strip(string source)
{
if (String.IsNullOrWhiteSpace(source))
{
return String.Empty;
}
return source;
}
Related
I'm trying to build a custom commandline for my app, i have several basic commands, and i simply use bunch of "if" statements to check what the command is. currently it looks something like this
public void ExecuteCommand()
{
string input = ReadLine(); //gets last string from input
bool isDone = false; //need bool to check whether command was executed or no, by default false.
Match result = Regex.Match(input, #"([^\s]+)"); //to get command name
string commandName = result.Value.ToLower();
string value = Regex.Match(input, #"\s(.*)").Value; //to get its parameter. currently everything after ' ' space.
if (commandName == "close")
{
Close(); isDone = true;
}
//so commandline is separate window, and appendedForm is a main form. in which some functions are executed.
if (commandName == "exit")
{
appendedForm.Close();
}
if (commandName == "spoof")
{
appendedForm.Fn_Spoof();
isDone = true;
}
if(commandName == "spoofstop")
{
appendedForm.Fn_StopCapture();
isDone = true;
}
if(commandName == "scan")
{
appendedForm.Fn_Scan(); isDone = true;
}
if(commandName == "clear")
{
output.Text = "";
WriteLine("Console cleared. Cache is empty.");
//data_lines.Clear();
isDone = true;
}
...
}
So that's basically it. I have a mainForm, and commandline form. string input is typed into commandline, then I check the name of command and execute some function from mainForm.
My question is, what is the best way of implementing such kind of thing? I surely can just continue writing bunch of "if"s, but something tells me that it's not the best way to make it.
I've thought of creating class "Command"
public class Command
{
public string name;
public string description;
public bool hasParameter;
Command()
{
}
}
And storing all commands in some sort of array, but I am not sure how would I use this to call a function from mainForm.
Any ideas are welcome!
You could stuff all commands into a Dictionary<string, someDelegate>; if you can live with all commands having the same return type.
I have used string and set up a few commands.
I make use of the params keyword to avoid the ugly new object[] on each call.
You still need to cast the arguments, unless you can make them all one type. (Which may actually be not such a bad idea, as they all come from an input string..)
Here is an example:
public delegate string cmdDel(params object[] args);
Dictionary<string, cmdDel> cmd = new Dictionary<string, cmdDel>();
Add a few functions:
cmd.Add("clear", cmd_clear);
cmd.Add("exit", cmd_exit);
cmd.Add("add", cmd_add);
cmd.Add("log", cmd_log);
With these bodies:
public string cmd_clear(params object[] args)
{
return "cleared";
}
public string cmd_exit(params object[] args)
{
return "exit";
}
public string cmd_add(params object[] args)
{
return ((int)args[0] + (int)args[1]).ToString();
}
public string cmd_log(params object[] args)
{
StringBuilder log = new StringBuilder();
foreach (object a in args) log.Append(a.ToString() + " ");
return log.ToString();
}
And test:
Console.WriteLine(cmd["clear"]());
Console.WriteLine(cmd["add"]( 23, 42));
Console.WriteLine(cmd["log"]( 23, "+" + 42, "=", cmd["add"]( 23, 42) ));
Console.WriteLine(cmd["exit"]());
cleared
65
23 + 42 = 65
exit
Of course you still need to use (at least) as many lines for setup as you have commands. And also need to do a similar amount of error checking.
But the command processing part can get pretty simple.
We are currently working on a logging solution and have implemented an extension method call 'Log'. When writing to the log file, we would ideally like to write the original variable name (rather than the variable name used in the extension method).
What we are currently having to do for this is:
public void DoSomeWork()
{
String testString = "Hey look I'm a string!";
testString.Log("testString value");
}
With the extention method:
public static String Log(this String valueToStore, String name)
{
// The logging code which uses the 'name' parameter
}
The issue here is that it becomes difficult to read on longer lines of code and looks clustered. What would be ideal is this:
public void DoSomeWork()
{
String testString = "Hey look I'm a string!";
testString.Log();
}
With the extension method:
public static String Log(this String valueToStore)
{
// The logging code which is able to retrieve the
// value 'testString' from the 'valueToStore' value
}
Is this at all possible by using Reflection? I'm aware of the nameofoption, but that only returns the string 'valueToStore' when used in the extension method.
Well, short answer is no. The variable names are not guaranteed to persist after compilation in unchanged form. That information would have to be somehow persisted (for example by the use of nameof()). Also, the variable name might not exist ("test".GetVarName()).
The long answer is: yes, possibly, but it's one of the most ridiculous things I've created in my life:
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
namespace Test1
{
class Program
{
static void Main(string[] args)
{
var myVarName = "test";
myVarName.Test();
Console.ReadKey();
}
}
static class Extensions
{
public static void Test(
this string str,
[System.Runtime.CompilerServices.CallerMemberName] string memberName = "",
[System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "",
[System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0
)
{
var relevantLine = File.ReadAllLines(sourceFilePath)[sourceLineNumber-1];
var currMethodName = MethodInfo.GetCurrentMethod().Name;
var callIndex = relevantLine.IndexOf(currMethodName + "()");
var sb = new Stack<char>();
for (var i = callIndex - 2; i >= 0; --i)
{
if (Char.IsLetterOrDigit(relevantLine[i]))
{
sb.Push(relevantLine[i]);
}
}
Console.WriteLine(new String(sb.ToArray()));
}
}
}
C# 10 has CallerArgumentExpressionAttribute that will do just that
public static void PrintNameAndValue(
this object obj,
[System.Runtime.CompilerServices.CallerArgumentExpression("obj")] string callerExp = ""
)
{
Console.WriteLine(callerExp + " = " + obj.ToString());
}
It'll capture the entire expression passed:
public void TestPrintNameAndValue()
{
string mystring = "test";
int myint = 5;
mystring.PrintNameAndValue(); // mystring = test
myint.PrintNameAndValue(); // myint = 5
(myint + 10).PrintNameAndValue(); // myint + 10 = 15
mystring.ToUpper().PrintNameAndValue(); // mystring.ToUpper() = TEST
}
You can use an Expression to achieve that, but performance-wise it may not be the best option:
public static void Log<T>(Expression<Func<T>> expr)
{
var memberExpr = expr.Body as MemberExpression;
if (memberExpr == null)
return;
var varName = memberExpr.Member.Name;
var varData = expr.Compile()();
// actual logging
...
}
Usage:
var test = "Foo";
Log(() => test);
Alternatively, if you're using C# 6.0, it can get a bit better using the nameof operator:
test.Log(nameof(test));
A better solution would be one that is leveraging the compiler abilities (specifically, the "Roslyn" compiler) and provide the member name on compile time.
Not really an answer, more of a pointer, but you could try doing something with your application that you're using(e.g. visual studio) instead of doing it in code. What I mean is make it rewrite everything that looks like [variable].Log(); to [variable].Log([variable])
I am pretty sure that there has to be some weird macro or plugin which does this for you before compiling.
I have a problem with calling a string from another method from the same script. I'm not sure if this is possible with C#
Sorry I'm new to C# but I used to do this in Objective-C so maybe its possible here?
So, the below code is the method I'm trying to use that string into.
This method checked if a message is passed in the game and execute the code.
void HandleMessage(string message, string metadata)
{
if (message == "UnlockName")
{
}
}
This is the method that contains the string needed (txt)
void OutputText( string txt ) {
//string firstName = lastLoadedLevel.contact.name.Split(new char[] { ' ' })[0];
//txt = txt.Replace("C:", firstName + ":");
txt = txt.Replace("D:", "D's name:");
txt = txt.Replace("[name]", PlayerPrefs.GetString("name"));
chat.AddText( txt, delegate {
options.gameObject.SetActive( true );
} );
}
Right now it contains (txt.Replace) which happens automaticlly throughout the text output.
I want to do the same in (void HandleMessage) to only do the replace code when the message "UnlockName" is passed.
The 2 commented lines here are what I need to use but I don't know how to use them in the first method.
Any help would be great :)
Thank you in advance.
Something like this maybe:
string HandleMessage(string message, string txt)
{
if (message == "UnlockName")
{
string firstName = lastLoadedLevel.contact.name.Split(new char[] { ' ' })[0];
return txt.Replace("C:", firstName + ":");
}
}
void OutputText(string txt, string message)
{
txt = HandleMessage(message, txt);
txt = txt.Replace("D:", "D's name:");
txt = txt.Replace("[name]", PlayerPrefs.GetString("name"));
chat.AddText(txt, delegate
{
options.gameObject.SetActive(true);
});
}
Might need some tweaking, I made some guesses on how you might be using things.
If nothing else, it should give you the concept of one way to pass strings in and back out of a method. You could also keep the void signature and pass in the string to be manipulated as a ref parameter.
So what I really want is somewhat usable tab completion in a PS module.
ValidateSet seems to be the way to go here.
Unfortunately my data is dynamic, so I cannot annotate the parameter with all valid values upfront.
DynamicParameters/IDynamicParameters seems to be the solution for that problem.
Putting these things together (and reducing my failure to a simple test case) we end up with:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Management.Automation;
using System.Text;
using System.Threading.Tasks;
namespace PSDummy
{
[Cmdlet(VerbsCommon.Get, "BookDetails")]
public class GetBookDetails : Cmdlet, IDynamicParameters
{
IDictionary<string, string[]> m_dummyData = new Dictionary<string, string[]> {
{"Terry Pratchett", new [] {"Small Gods", "Mort", "Eric"}},
{"Douglas Adams", new [] {"Hitchhiker's Guide", "The Meaning of Liff"}}
};
private RuntimeDefinedParameter m_authorParameter;
private RuntimeDefinedParameter m_bookParameter;
protected override void ProcessRecord()
{
// Do stuff here..
}
public object GetDynamicParameters()
{
var parameters = new RuntimeDefinedParameterDictionary();
m_authorParameter = CreateAuthorParameter();
m_bookParameter = CreateBookParameter();
parameters.Add(m_authorParameter.Name, m_authorParameter);
parameters.Add(m_bookParameter.Name, m_bookParameter);
return parameters;
}
private RuntimeDefinedParameter CreateAuthorParameter()
{
var p = new RuntimeDefinedParameter(
"Author",
typeof(string),
new Collection<Attribute>
{
new ParameterAttribute {
ParameterSetName = "BookStuff",
Position = 0,
Mandatory = true
},
new ValidateSetAttribute(m_dummyData.Keys.ToArray()),
new ValidateNotNullOrEmptyAttribute()
});
// Actually this is always mandatory, but sometimes I can fall back to a default
// value. How? p.Value = mydefault?
return p;
}
private RuntimeDefinedParameter CreateBookParameter()
{
// How to define a ValidateSet based on the parameter value for
// author?
var p = new RuntimeDefinedParameter(
"Book",
typeof(string),
new Collection<Attribute>
{
new ParameterAttribute {
ParameterSetName = "BookStuff",
Position = 1,
Mandatory = true
},
new ValidateSetAttribute(new string[1] { string.Empty }/* cannot fill this, because I cannot access the author */),
new ValidateNotNullOrEmptyAttribute()
});
return p;
}
}
}
Unfortunately this tiny snippet causes a lot of issues already. Ordered descending:
I fail to see how I can create a connection between the parameters. If you pick an author, you should only be able to pick a book that matches the author. So far GetDynamicParameters() always seems stateless though: I see no way to access the value of a different/earlier dynamic parameter. Tried keeping it in a field, tried searching MyInvocation - no luck. Is that even possible?
How do you define a default value for mandatory parameter? Doesn't fit the silly example, but let's say you can store your favorite author. From now on I want to default to that author, but having a pointer to an author is still mandatory. Either you gave me a default (and can still specify something else) or you need to be explicit.
Tab completion for strings with spaces seems weird/broken/limited - because it doesn't enclose the value with quotes (like cmd.exe would do, for example, if you type dir C:\Program <tab>). So tab completion actually breaks the invocation (if the issues above would be resolved, Get-BookDetails Ter<tab> would/will expand to Get-BookDetails Terry Pratchett which puts the last name in parameter position 1 aka 'book'.
Shouldn't be so hard, surely someone did something similar already?
Update: After another good day of tinkering and fooling around I don't see a way to make this work. The commandlet is stateless and will be instantiated over and over again. At the point in time when I can define dynamic parameters (GetDynamicParameters) I cannot access their (current) values/see what they'd be bound to - e.g. MyInvocation.BoundParameters is zero. I'll leave the question open, but it seems as if this just isn't supported. All the examples I see add a dynamic parameter based on the value of a static one - and that's not relevant here. Bugger.
I think this works. Unfortunately, it uses reflection to get at some of the cmdlet's private members for your first bullet. I got the idea from Garrett Serack. I'm not sure if I completely understood how to do the default author, so I made it so that the last valid author is stored in a static field so you don't need -Author the next time.
Here's the code:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Management.Automation;
using System.Text;
using System.Threading.Tasks;
namespace PSDummy
{
internal class DynParamQuotedString {
/*
This works around the PowerShell bug where ValidateSet values aren't quoted when necessary, and
adding the quotes breaks it. Example:
ValidateSet valid values = 'Test string' (The quotes are part of the string)
PowerShell parameter binding would interperet that as [Test string] (no single quotes), which wouldn't match
the valid value (which has the quotes). If you make the parameter a DynParamQuotedString, though,
the parameter binder will coerce [Test string] into an instance of DynParamQuotedString, and the binder will
call ToString() on the object, which will add the quotes back in.
*/
internal static string DefaultQuoteCharacter = "'";
public DynParamQuotedString(string quotedString) : this(quotedString, DefaultQuoteCharacter) {}
public DynParamQuotedString(string quotedString, string quoteCharacter) {
OriginalString = quotedString;
_quoteCharacter = quoteCharacter;
}
public string OriginalString { get; set; }
string _quoteCharacter;
public override string ToString() {
// I'm sure this is missing some other characters that need to be escaped. Feel free to add more:
if (System.Text.RegularExpressions.Regex.IsMatch(OriginalString, #"\s|\(|\)|""|'")) {
return string.Format("{1}{0}{1}", OriginalString.Replace(_quoteCharacter, string.Format("{0}{0}", _quoteCharacter)), _quoteCharacter);
}
else {
return OriginalString;
}
}
public static string[] GetQuotedStrings(IEnumerable<string> values) {
var returnList = new List<string>();
foreach (string currentValue in values) {
returnList.Add((new DynParamQuotedString(currentValue)).ToString());
}
return returnList.ToArray();
}
}
[Cmdlet(VerbsCommon.Get, "BookDetails")]
public class GetBookDetails : PSCmdlet, IDynamicParameters
{
IDictionary<string, string[]> m_dummyData = new Dictionary<string, string[]>(StringComparer.OrdinalIgnoreCase) {
{"Terry Pratchett", new [] {"Small Gods", "Mort", "Eric"}},
{"Douglas Adams", new [] {"Hitchhiker's Guide", "The Meaning of Liff"}},
{"An 'Author' (notice the ')", new [] {"A \"book\"", "Another 'book'","NoSpace(ButCharacterThatShouldBeEscaped)", "NoSpace'Quoted'", "NoSpace\"Quoted\""}} // Test value I added
};
protected override void ProcessRecord()
{
WriteObject(string.Format("Author = {0}", _author));
WriteObject(string.Format("Book = {0}", ((DynParamQuotedString) MyInvocation.BoundParameters["Book"]).OriginalString));
}
// Making this static means it should keep track of the last author used
static string _author;
public object GetDynamicParameters()
{
// Get 'Author' if found, otherwise get first unnamed value
string author = GetUnboundValue("Author", 0) as string;
if (!string.IsNullOrEmpty(author)) {
_author = author.Trim('\'').Replace(
string.Format("{0}{0}", DynParamQuotedString.DefaultQuoteCharacter),
DynParamQuotedString.DefaultQuoteCharacter
);
}
var parameters = new RuntimeDefinedParameterDictionary();
bool isAuthorParamMandatory = true;
if (!string.IsNullOrEmpty(_author) && m_dummyData.ContainsKey(_author)) {
isAuthorParamMandatory = false;
var m_bookParameter = new RuntimeDefinedParameter(
"Book",
typeof(DynParamQuotedString),
new Collection<Attribute>
{
new ParameterAttribute {
ParameterSetName = "BookStuff",
Position = 1,
Mandatory = true
},
new ValidateSetAttribute(DynParamQuotedString.GetQuotedStrings(m_dummyData[_author])),
new ValidateNotNullOrEmptyAttribute()
}
);
parameters.Add(m_bookParameter.Name, m_bookParameter);
}
// Create author parameter. Parameter isn't mandatory if _author
// has a valid author in it
var m_authorParameter = new RuntimeDefinedParameter(
"Author",
typeof(DynParamQuotedString),
new Collection<Attribute>
{
new ParameterAttribute {
ParameterSetName = "BookStuff",
Position = 0,
Mandatory = isAuthorParamMandatory
},
new ValidateSetAttribute(DynParamQuotedString.GetQuotedStrings(m_dummyData.Keys.ToArray())),
new ValidateNotNullOrEmptyAttribute()
}
);
parameters.Add(m_authorParameter.Name, m_authorParameter);
return parameters;
}
/*
TryGetProperty() and GetUnboundValue() are from here: https://gist.github.com/fearthecowboy/1936f841d3a81710ae87
Source created a dictionary for all unbound values; I had issues getting ValidateSet on Author parameter to work
if I used that directly for some reason, but changing it into a function to get a specific parameter seems to work
*/
object TryGetProperty(object instance, string fieldName) {
var bindingFlags = System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public;
// any access of a null object returns null.
if (instance == null || string.IsNullOrEmpty(fieldName)) {
return null;
}
var propertyInfo = instance.GetType().GetProperty(fieldName, bindingFlags);
if (propertyInfo != null) {
try {
return propertyInfo.GetValue(instance, null);
}
catch {
}
}
// maybe it's a field
var fieldInfo = instance.GetType().GetField(fieldName, bindingFlags);
if (fieldInfo!= null) {
try {
return fieldInfo.GetValue(instance);
}
catch {
}
}
// no match, return null.
return null;
}
object GetUnboundValue(string paramName) {
return GetUnboundValue(paramName, -1);
}
object GetUnboundValue(string paramName, int unnamedPosition) {
// If paramName isn't found, value at unnamedPosition will be returned instead
var context = TryGetProperty(this, "Context");
var processor = TryGetProperty(context, "CurrentCommandProcessor");
var parameterBinder = TryGetProperty(processor, "CmdletParameterBinderController");
var args = TryGetProperty(parameterBinder, "UnboundArguments") as System.Collections.IEnumerable;
if (args != null) {
var currentParameterName = string.Empty;
object unnamedValue = null;
int i = 0;
foreach (var arg in args) {
var isParameterName = TryGetProperty(arg, "ParameterNameSpecified");
if (isParameterName != null && true.Equals(isParameterName)) {
string parameterName = TryGetProperty(arg, "ParameterName") as string;
currentParameterName = parameterName;
continue;
}
// Treat as a value:
var parameterValue = TryGetProperty(arg, "ArgumentValue");
if (currentParameterName != string.Empty) {
// Found currentParameterName's value. If it matches paramName, return
// it
if (currentParameterName.Equals(paramName, StringComparison.OrdinalIgnoreCase)) {
return parameterValue;
}
}
else if (i++ == unnamedPosition) {
unnamedValue = parameterValue; // Save this for later in case paramName isn't found
}
// Found a value, so currentParameterName needs to be cleared
currentParameterName = string.Empty;
}
if (unnamedValue != null) {
return unnamedValue;
}
}
return null;
}
}
}
For security reasons, I don't want specific method to receive non-programmer or non-compiler time strings, how could I do this?
readonly String OK_STR = "some text";
String BAD_STR = "another text";
public void SetSecureStr(String str)
{
//Use the string for security purpose
}
//Somewhere in the code
SetSecureStr(OK_STR); //Accepted
SetSecureStr(OK_STR + "Programmer passed this staticlly!"); //Accepted (If not possible to implement, forget about it)
SetSecureStr(BAD_STR); //Throw exception, BAD_STR is modifiable
SetSecureStr(OK_STR + untrustedVar); //Throw exception, concatenation with modifiable
SetSecureStr(String.Format("{0}", OK_STR)); //Throw exception, not const
It may be better to whitelist against things inside your ability to control, such as enums or local constants (or a local whitelist from configuration data if the list isn't fixed ahead of time).
As a rough check, you could check whether it is interned, since all literals will be interned automatically via ldstr; but note you can explicitly intern too, so this isn't 100% safe.
And of course, in any event with the question as asked, if that string happens somewhere else as a literal (unconnected to this code) it would still be trusted. I suggest a whitelist is safer...
A whitelist could be as simple as:
private static readonly HashSet<string> whiteList = new HashSet<string> {
"good", "more good"
};
... check via whiteList.Contains(s)
but note that this is still mutable at runtime (via reflection if necessary).
Instead of accepting string values, number all your strings, and pass the number:
string[] good_strings = {"some text"};
public void SetSecureStr(int stringno)
{
string s = good_strings[stringno];
}
Computed strings won't be supported with that approach.
I came finally with a solution which is hybrid between the two previously proposed answers:
public class SqlQuery
{
private SqlQuery() { }
private static UInt32 sqlQueriesCount = 0;
public static UInt32 INBOUND_UPDATE_CALLBACK_NUM = sqlQueriesCount++;
public static UInt32 INBOUND_UPDATE_DEST_ADDR_SUBUNIT = sqlQueriesCount++;
public static UInt32 INBOUND_UPDATE_DEST_BEARER_TYPE = sqlQueriesCount++;
//...etc
private static readonly Dictionary<UInt32, String> queries = new Dictionary<UInt32, String>
{
{SqlQuery.INBOUND_UPDATE_CALLBACK_NUM, "UPDATE inbound SET callbackNum = ? WHERE id = ?"},
{SqlQuery.INBOUND_UPDATE_DEST_ADDR_SUBUNIT, "UPDATE inbound SET destAddrSubunit = ? WHERE id = ?"},
{SqlQuery.INBOUND_UPDATE_DEST_BEARER_TYPE, "UPDATE inbound SET destBearerType = ? WHERE id = ?"},
//...etc
};
public static String GetQueryText(UInt32 queryKey)
{
String query = null;
if (SqlQuery.queries.TryGetValue(queryKey, out query) == false)
{
throw new ArgumentOutOfRangeException(String.Format("Query must be paramerized query stored within SqlQuery class, provided queryKey: {0}", queryKey));
}
return query;
}
}
Usage:
OdbcCommand cmd = new OdbcCommand(SqlQuery.GetQueryText(SqlQuery.INBOUND_UPDATE_CALLBACK_NUM), con);