Coming from PHP, I have never written C# before and I have encountered something like this in C#:
public string rule(string playerId, string action, params string[] optionalData){
...
}
and in PHP it is like this
public function rule($playerId, $action, $optionalData=array()){
...
}
In PHP I simply fill out the parameter for the $optionalData like this...
myVar->rule("123", "myAction", array('url'=>'review.com');
However in C# I am not sure how to fill the optionalData (params string[] optionalData) parameter as it is a key value parameter (like in the PHP example). My question is how do I create a key value array like the PHP that I created in my example and put into the parameter?
CoolClass cc = new CoolClass();
cc.rule("123", "myAction", ???);
I was searching google and was looking at dictionary and hashmaps etc but I am guessing it is an overkill or it does not work..
Many thanks!
When you were looking at dictionaries, you were definitely looking at the right facility.
If rule() in C# is in your own code, may I recommend changing the signature to:
public string rule(string playerId, string action, IDictionary<string, string> optionalData = new Dictionary<string, string>()){
...
}
What this allows you to do:
Operate on the values in optionalData the way that other C# programmers will expect.
The = new Dictionary<string, string>() part of the suggested method signature make the parameter truly optional. It will not be necessary when calling the method.
You can use IDictionary<T> methods to work with the data. Some syntax you should be somewhat familiar with (consider accessing by key optionalData["someString"].)
However, if rule() is not in your code, you would leave out the optionalData by simply omitting parameters. Examples of valid calls of the original C# method in your question:
rule("Bob", "load")
rule("Bob", "load", "url", "www.example.com") (In this case, optionalData[0].Equals("url", StringComparisonOptions.Ordinal) and optionalData[1].Equals("www.example.com", StringComparisonOptions.Ordinal) is true.
One thing to consider about the original method - keep in mind that rule("Bob", "load", 'url") is a valid call, and you would need to have a run-time check to make sure you had the right number of parameters. Another plus to using a Dictionary<TKey, TValue>. You may even consider writing an adapter method to the original rule(), if you can't change it.
You can use a Dictionary:
Dictionary<string,string[]>
or something like:
Dictionary<int, string[]>
I believe dictionary will work in your case.
You can use Dictionary <key_datatype, value_datatype> .
Example:
Your method definition here :
public string rule(string playerId, string action, Dictionary<string, string> optionalData){
...
}
Method call:
Dictionary<string, string> optionalData = new Dictionary<string, string>();
optionalData.Add("url", "review.com");
cc.rule("123", "myAction", optionalData);
Or
you can use DynamoObject to make it more easier to write:
dynamic optionalData = new ExpandoObject();
//The token after the dynamoObject period will be the key to the assigned value.
optionalData.url = "review.com";
cc.rule("123", "myAction", optionalData);
Your method can get the key-value pairs like this:
public string rule(string playerId, string action, dynamic optionalData)
{
...
foreach (var pair in (IDictionary<string, object>)optionalData)
{
if (group.Key == "url")
{
Console.WriteLine(group.Value);
}
else if (group.Key == "post")
{
Console.WriteLine(group.Value);
}
}
}
Related
I'm looking for a way to define a dictionary for reuse. ie. I can create the dictionary object without having to populate it with the values I want.
Here is what I have currently (note code not tested, just example)
public Dictionary<string, string> NewEntryDictionary()
{
Dictionary<string, string> dic = new Dictionary<string, string>();
// populate key value pair
foreach(string name in Enum.GetNames(typeof(Suits))
{
dic.Add(name, "");
}
return dic;
}
The end result should be a new dictionary object with a predefined set of keys.
But I want to avoid doing it this way.
It's not really clear whether you're concerned about the amount of code you've written, or the efficiency of it. From an efficiency perspective, it's fine - it's O(N), but that's hard to avoid if you're populating a dictionary with N entries.
You can definitely make the source code shorter though, using LINQ:
public Dictionary<string, string> NewEntryDictionary()
{
return Enum.GetNames(typeof(Suits)).ToDictionary(name => name, name => "");
}
That won't be any more efficient, of course... it's just shorter code.
If you do ONLY want to save values according to your enum, use
Dictionary<Suits,String> instead of Dictionary<String,String>
Everything else, Jon already said. Use LinQ for a bit more "fancy" look. But that does not do better performance
This is probably a very simple question but google has let me down sofar and keeps pointing me towards python solutions.
I have a webpage where applciations/users can supply querystringparameters.To Retrieve the querystring parameters I use the following code:
IDictionary<string, string> qStrings = HtmlPage.Document.QueryString;
to check the presence of a specified key, I use the following code:
if (!String.IsNullOrEmpty(qStrings["PARAM1"]))
{}
Knowing our users, i'm expecting them to give parameterkeys as follows: "Param1", "param1", "pArAm1"
How can simply cast every key in a dictionary to uppercase without iterating each key-valuepair?
Or how can i alter the qStrings["PARAM1"] so it ignores the case?
You can use StringComparer to find keys ignoring their case:
var qStrings = new Dictionary<string, string>(
HtmlPage.Document.QueryString,
StringComparer.OrdinalIgnoreCase)
Simplest Way
qStrings = qStrings .ToDictionary(k => k.Key.ToUpper(), k => k.Value.ToUpper());
Maybe you can do it like below:
Dictionary<string, string> qStrings = new Dictionary<string, string>();
foreach (var a in qStrings.Keys)
{
switch (a.ToUpper())
{
case "PARAM1":
break;
}
}
Without iterating is not possible. No matter what approach you use there is going to be some sort of iteration. The this is you need to limit the insertion of the data to a single unified casing rather than allowing users to input all sorts of casing.
Taking your example: "Param1", "param1", "pArAm1", a key will be created for each single one of these as they are treated as separate entities. The best way to handle that is to force the casing at the insertion rather than when querying for values.
For example:
void AddToDictionary(string key, string value)
{
qStrings[key.ToUpper()] = value;
}
This is a very straight forward question.
I have a Content-Type stored in the form of a string.
Ideally I'd like to infer an extension from that Content-Type without having to have a giant nasty switch case.
Is there a built in construct to achieve this?
Btw, I found this question but that goes the opposite direction from extension to content-type.
You'll want a Dictionary. This will allow you to look up an extension for a given content type:
Dictionary<string, string> extensionLookup = new Dictionary<string, string>()
{
{"ContentType1", ".ext1"},
{"ContentType2", ".ext2"},
};
You can populate the dictionary based on a database table, a file, etc. rather than hard coding the values.
Once you have the Dictionary it's as simple as:
string extension = extensionLookup[someContentType];
In the registry of my W10 box there is an extensive list mapping content-type to .extn:
[HKEY_CLASSES_ROOT\MIME\Database\Content Type]
You might like to explore the HtmlAgilityPack OSS project which has source file HtmlWeb.cs containing the following methods:
public static string GetContentTypeForExtension(string extension, string def)
public static string GetExtensionForContentType(string contentType, string def)
There is also [commented-out] Dictionary and population code:
//private static Dictionary<string, string> _mimeTypes;
// _mimeTypes = new Dictionary<string, string>();
// _mimeTypes.Add(".3dm", "x-world/x-3dmf");
// _mimeTypes.Add(".3dmf", "x-world/x-3dmf");
// ...
// _mimeTypes.Add(".zoo", "application/octet-stream");
// _mimeTypes.Add(".zsh", "text/x-script.zsh");
So you may brew your own (maybe just the common ones that YOUR app needs) for efficiency.
FYI the authoritative list of content-type values and usage is here:
www.iana.org/assignments/media-types/media-types.xhtml
Actually I need something like List<KeyValuePair<T, U>> but I want to be able to initialize it like dictionary (i.e. without writing new KeyValuePair every time). Like this:
Dictionary<string, string> dic = new Dictionary<string, string>
{
{ "key1", "value1"},
{ "key2", "value2"}
};
EDIT: It turns out .NET does have a combination list/dictionary type already: OrderedDictionary. Unfortunately this is a non-generic type, making it rather less attractive in my view. However, it retains the insertion order if you just call Add repeatedly.
It's a little strange as calling Add does not affect entries where a key already exists, whereas using the indexer to add a key/value pair will overwrite a previous association. Basically it doesn't seem like a terribly nice API, and I would personally still avoid it unless your use case exactly matches its behaviour.
No, .NET doesn't have any insertion-order-preserving dictionaries. You could always write your own list-based type with the relevant Add method. This might even be one of the few places I'd consider extending an existing type:
public class KeyValueList<TKey, TValue> : List<KeyValuePair<TKey, TValue>>
{
public void Add(TKey key, TValue value)
{
Add(new KeyValuePair<TKey, TValue>(key, value));
}
}
Then:
var list = new KeyValueList<string, string>
{
{ "key1", "value1"},
{ "key2", "value2"}
};
An alternative is to use composition, but my gut feeling is that this is a reasonable use of inheritance. I can't place why I'm happy in this case but not usually, mind you...
Because you do not have a dictionary you cannot use a dictionary initiailzer. You have a list so you could use a list initializer which will be the closest you could get:
var l = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("key1", "value1"),
new KeyValuePair<string, string>("key2", "value2"),
};
Here's the minimum requirement for you to use dictionary initializer: the class must implement IEnumerable and the class must have a public method Add which takes 2 arguments (where the first argument represents the key and the second argument the value). So you could write a custom class which satisfies those requirements and you will be able to use the syntax you have shown in your question.
The code you have typed works fine - further to Mads Togersen's post about the implementation of collection initialisers, the compiler maps the brace-delimited entries ({"key1", "value1"} above) to an Add method on the collection with the same signature - in this case Dictionary.Add(TKey, TValue).
I have a lot of functions that look like this. Each has N arguments and each creates an SQLparamater array with each paramater being of this very similar form.
[WebMethod]
public static string accessServer(string dataField1, string dataField2, string dataField3) {
string value;
SQLParamater[] param = new SQLParameter[len] // len is the amount of arguments
param[0] = new SQLParameter("#dataField1", dataField1);
param[1] = new SQLParameter("#dataField2", dataField2);
param[2] = new SQLParameter("#dataField3", dataField3);
...
// do something with param
return value;
}
This looks like it can be done generically using a combination of Reflection and accessing the paramaters in a generic way.
Ideally a method of the form
public static SQLParamater[] getParams(someType paramaters)
and SQLParamater[] param = getParams(...)
I'm not sure how to pass on all the paramaters generically.
[Edit]
Note that the names of these datafields are important. It's not just an array of strings but rather a set of key/value pairs.
[/Edit]
You can use a function with variable arguments: name(params string[] arguments), so you can call, for example: name(arg1,arg2,arg3,arg4);
This has been asked about before (can't find that question though), the problem however is that while you can figure out the parameter names by using reflection MethodBase.GetCurrentMethod() you can't zip those names together with the parameter values because there's no way for you to access a parameter list of values.
There are other ways of trying to work around this very specific tiresome problem but I don't recommend doing it this way, it just doesn't make a lot of sense.
Now, given a method like this:
static void SomeMethod(string arg1, int arg2, object arg3)
{
}
You could do this:
static void Main()
{
var b = 123;
// this now becomes necessary as it's the only way of getting at the metadata
// in a presumable safe manner
Expression<Action> x = () => SomeMethod("a", b, "a" + b);
var args = GetArgs(x);
foreach (var item in args)
{
Console.WriteLine("{0}: {1}", item.Key, item.Value);
}
}
And implement the GetArgs method like so (you still need a way of putting those values somewhere becuase the invocation never occurs):
static IDictionary<string, object> GetArgs(Expression<Action> x)
{
var args = new Dictionary<string, object>();
var m = (MethodCallExpression)x.Body;
var parameters = m.Method.GetParameters();
for (int i = 0; i < m.Arguments.Count; i++)
{
// an easy way of getting at the value,
// no matter the complexity of the expression
args[parameters[i].Name] = Expression
.Lambda(m.Arguments[i])
.Compile()
.DynamicInvoke();
}
return args;
}
You infer the collection of name/value pairs from the expression tree created by the compiler, it's doable but kind of odd.
I think your API design is flawed if you need this, you would better have one method, which accepts a collection of some sort.
Code duplication like this is almost never the correct way to get things done.
EDIT
On topic:
I guess you can get the values from the stack: http://www.thescarms.com/dotnet/StackFrame.aspx
we do it like this:
var dict=new Dictionary
{
{"#param1",value1},
{"#param2",value2},
{"#param3",value3},
{"#param4",value4},
....
};
DALayer.ExecuteProc("procName",dict);
In the ExecuteProc function you can iterate over Dictionary object and set params using KeyValuePair object. But if you have to setup the datatype, lengths etc for the parameters then you have to do more work like preparing the sql command to query about parameters or passing more complicated object as parameter that contains information about datatype, length and direction etc.