I just wonder if it's possible to change the key of a hashtable? And if so, how do i do it?
Here is the keys of my hashtable which i got by doing this:
var param = selectedGroup.Parameters.Keys;
so what i want to do is basically just change the key.
selectedGroup.Parameters.Keys[i].Value = newKey;
how do i do that?
I guess i have to move all the values beloning to that key somehow.
i tried to make a new hashtable like this
var parameters = new Tacton.Configurator.ObjectModel.SequencedHashtable<Tacton.Configurator.ObjectModel.Parameter>();
for (int i = 1; i < selectedGroup.Parameters.Count + 1; i++)
{
var para = result.Xml.SelectNodes("/session/view/parameters/param[" + i + "]/field")[0].InnerText + result.Xml.SelectNodes("/session/view/parameters/param[" + i + "]/desc-frags/frag[2]/#name")[0].Value;
var param = selectedGroup.Parameters[i];
parameters.Add(para, param);
}
but then i got the following error:
Unable to cast object of type 'Named`1[Tacton.Configurator.ObjectModel.Parameter,Tacton.Configurator.ObjectModel.Parameter]' to type 'Tacton.Configurator.ObjectModel.Parameter'.
i basically want the same hashtable as selectedGroup.Parameters but i want to change the keys from
handsender_part_qty_multifieldITM_HANDSENDER_N002592U00U01 to
handsender_part_qty_multifieldITM_HANDSENDER_N002592-00-01
this is what selectedGroup.Parameters[i] looks like:
In most versions of "hashtables", there is no way of changing the key of an entry. This is because the key's hash value is very important. Changing key almost always changes the hash value and the entries would have to be moved around identically as if you removed old entry and re-added new entry with new key.
This is why, usually, there is no way of 'editing' the key. Instead, typical hashtables force you to expicitely remove and then add the entry back. Look at the classical .Net's Dictionary for an example of that.
Now, as for your piece of code, this is a pure guesswork. I couldn't find anything related to Tacton/SequencedHashtable on the internet, so I couldn't review its API, so from my point of view, there may be furry dragons inside and yourhash.Add(foo) may format your harddrive just for fun.
However, basing on your requirement:
i basically want the same hashtable as selectedGroup.Parameters but i want to change the keys from handsender_part_qty_multifieldITM_HANDSENDER_N002592U00U01 to handsender_part_qty_multifieldITM_HANDSENDER_N002592-00-01
and on the "general idea of a hashtable" and on the assumption that this hashtable has some reasonable API that is designed so a typical .Net developer wouldn't bite his hands off using it, please try some typical things:
var parameters = new SequencedHashtable<Parameter>();
foreach(var par in selectedGroup.Parameters)
{
var newname = par.Name.Replace("U", "-");
// try changing the parameter's name:
par.Name = newname;
parameters.Add(par);
}
or
...
// try adding the parameter under new name:
par.Name = newname;
parameters.Add(newname, par);
...
or
...
// try cloning the parameter with new name:
var newpar = new Parameter(newname, par.config1, par.option2, par.foobar3, ...)
parameters.Add(newpar);
...
This is just a sketch. You may need to find the correct overload of 'Add' method. Maybe you will need to use 'Insert' instead. It may turn out that the hashtable doesn't support adding - then check its constructors. Maybe there's some constructor that takes a List of Parameters?
var parameters = new List<Parameter>(); <---- INTO a temporary list
foreach(var par in selectedGroup.Parameters)
{
var newpar = ..par or clone of par..
....edits, fixes to the newpar
parameters.Add(newpar);
}
var myNewParams = new SequencedHashtable<Parameter>( parameters );
etc. Unfortunatelly, most of the job is on your side - you have to review hte hashtable's API, you have to check if/how to edit the param's name, and/or how to clone the parameter so that all bits are preserved.
...or if you could point out where I/We can read the docs, then maybe someone will look at them. I have not found them, sorry.
Related
I'm creating several maps to cache some info for my application.
When some events are triggered I want to clear those caches.
I have a list of all maps names I should clear but I couldn't find a way to dynamically get those maps in order to clear them. Basically I have:
var mapsNames = ["map-1", "map-2", "map-3"];
And I want a simple way of doing things like:
var client = HazelcastClient.NewHazelcastClient();
foreach (var name in mapsNames)
{
var map = client.GetMap(name);
map.Clear();
}
In the README.md we do have some examples like:
var client = HazelcastClient.NewHazelcastClient();
var personnelMap = client.GetMap("personnelMap");
personnelMap.Put("Alice", "IT");
personnelMap.Put("Bob", "IT");
personnelMap.Put("Clark", "IT");
Console.WriteLine("Added IT personnel. Logging all known personnel");
foreach(var entry in personnelMap.entrySet())
{
Console.WriteLine("{0} is in {1} department", entry.Key, entry.Value );
}
client.Shutdown();
That indicates we should have a method GetMap that is non-generic but I couldn't find it. The only one avaiable is GetMap<TKey, TValue>. Are the docs wrong? Is there a way to get a Map by its name without using some ugly reflection?
Thanks in advance,
Did you try (ICollection<IDistributedObject> GetDistributedObjects()) https://github.com/hazelcast/hazelcast-csharp-client/blob/v3.12.1/Hazelcast.Net/Hazelcast.Client/HazelcastClient.cs#L230 ?
You can iterate through all the existing maps, and you can use https://github.com/hazelcast/hazelcast-csharp-client/blob/v3.12.1/Hazelcast.Net/Hazelcast.Core/IDistributedObject.cs#L53 to check is the distributed object is of type map service.
Im trying to convert my List code lines to Dictionary since as i understand they are faster, and more easy to manage, like i can get its value with its key value rather than just index.
Thus, im trying to modify my json-deserializing code (which actually,Newtonsoft's), but i have no idea how can i convert raw json to dictionary with my own format.
Dictionary <string,Tag>
Tag class is my own class with member variables, contains tag informations.
it doesnt includes functions for sure.
String should be Tag.Name, a string member variable.
//TODO: Fix "Hacky" solution to deserialized lines into Dictionary
//Which means : Raw Json -> Deserialized data -> List -> Dictionary is very hacky in my perspective
//Should be : Raw Json -> Deserialized data -> Dictionary, but i have no idea to convert directly like that
else if (filename.Contains(".json")) // very janky method to detect json file. dont depend on file extension - rather depend on actual file format.
{
string line = String.Join("", Lines);
List<Tag> lv_list = new List<Tag>();
Dictionary<string,Tag> lv_dict = new Dictionary<string, Tag>();
lv_list = JsonConvert.DeserializeObject<List<Tag>>(line);
gVar.Tags.AddRange(lv_list);
gVar.gTagCount += lv_list.Count();
for (int i = 0; i < lv_list.Count(); ++i)
{
gVar.Tags2.Add(lv_list[i].Name, lv_list[i]);
}
int lv_tagcount = 1;
for (int i = 0; i < gVar.gTagCount; ++i)
{
gVar.Tags[i].TagCount = lv_tagcount;
++lv_tagcount;
}
I wouldn't bother deserializing directly to a Dictionary: if the JSON is formatted like an array, go ahead and deserialize it to a List first. There's nothing "hacky" about the two-step process.
Use LINQ's ToDictionary() method to get a dictionary from a list:
Dictionary<string,Tag> lv_dict = JsonConvert.DeserializeObject<List<Tag>>(line)
.ToDictionary(tag => tag.Name);
You seem to have a habit of initializing a variable with an empty collection that never gets used, and then setting the variable to some other value. This isn't helpful: just declare and set the variable at the same time. But based on this pattern I'm wondering if gVar is an object you're trying to initialize even though your code looks like it's trying to add things to that variable. Do you really want to do something more like this?
gVar.Tags2 = JsonConvert.DeserializeObject<List<Tag>>(line)
.ToDictionary(tag => tag.Name);
I'd also question whether the TagCount property is a good pattern. It looks like you're trying to make each Tag explicitly aware of its own position in the collection that it's found in. This is a code smell. Perhaps now that you're using a Dictionary that won't be necessary because you can look up the tag by its name in the Dictionary?
So, I feel like it's possible, but i don't have the chops to put it together. I have lookup tables (with ID and Name fields). I have enums that I keep in sync with the lookups. What I'd like is to make a list of SQL tables, and have roslyn create the enums during/before compile. this way I know my enums are always in sync, and it's one more thing off my plate.
Could someone out there show me the way, or tell me why it would be a bad idea? I feel like the solution isn't really a lot of code...
Thanks!
This is how you create enums with roslyn;
class Program
{
static void Main(string[] args)
{
var member1 = Syntax.EnumMemberDeclaration(
identifier: Syntax.Identifier("Member1")
);
var declaration = Syntax.EnumDeclaration(
identifier: Syntax.Identifier("MyEnum"),
modifiers: Syntax.TokenList(Syntax.Token(SyntaxKind.PublicKeyword)),
members: Syntax.SeparatedList(member1)
);
Console.WriteLine(declaration.Format());
Console.ReadLine();
}
}
this returns:
public enum MyEnum
{
Member1
}
Now to your question, I don't know if this is what you really need.
First I think there is not yet any built in functionality to do this at precompile, so you'd need to create a console exe and call it in your prebuild events.
So at this point probably it is a better idea to do this manually via code generation and not on every build, unless these tables are changing very frequently.
An in this case you don't really need roslyn to do it for you, you can just spit it out with any code generation software, or roll your own...
Here is some code updated for the current version of Roslyn and also shows adding attributes and values to the enum items.
public EnumDeclarationSyntax GenerateEnum()
{
var loanPurpose = new[]
{
"Business Launching",
"HomePurchase",
"HomeImprovement"
};
var enumDescriptions = new[]
{
"Launch a new business",
"Buy a home",
"Make home improvements"
};
var i = 0;
var members = new List<EnumMemberDeclarationSyntax>();
foreach (var item in loanPurpose)
{
var attribute = SyntaxFactory.Attribute(
SyntaxFactory.IdentifierName("Description"));
var attributeArgument = SyntaxFactory.AttributeArgument(
SyntaxFactory.LiteralExpression(
SyntaxKind.StringLiteralExpression,
SyntaxFactory.Literal(enumDescriptions[i ])));
attribute = attribute.WithArgumentList(
SyntaxFactory.AttributeArgumentList(
SyntaxFactory.SingletonSeparatedList(attributeArgument)));
var attributes = SyntaxFactory.SingletonList(
SyntaxFactory.AttributeList(SyntaxFactory
.SingletonSeparatedList(attribute)));
var objectCreationExpression = SyntaxFactory.EqualsValueClause(
SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression,
SyntaxFactory.Literal(i)));
var member = SyntaxFactory.EnumMemberDeclaration(attributes,
SyntaxFactory.Identifier(item),
objectCreationExpression);
members.Add(member);
i++;
}
var declaration = SyntaxFactory.EnumDeclaration
(new SyntaxList<AttributeListSyntax>(),
baseList: null,
identifier: SyntaxFactory.Identifier("LoanPurpose"),
modifiers: SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword)),
members: SyntaxFactory.SeparatedList(members)
);
return declaration;
}
The syntax for adding the attributes gets a little awkward but I find that I often need some attributes added. You probably already have the data for the attributes and values in the lookup tables driving the code generation.
The Answer provided by Sebastian 6 years ago likely used to work but no longer does.
New set of sample code to accomplish the same thing as of 18/12/2017
EnumMemberDeclarationSyntax member1 = EnumMemberDeclaration(identifier: Identifier("Member1"));
var members =new SyntaxNodeOrToken[]{member1};
var declaration = EnumDeclaration(
identifier: Identifier("MyEnum")).WithMembers(
members: SeparatedList< EnumMemberDeclarationSyntax>(members));
I am trying to make a change to a KeyValuePair and have got as far as this code from another post I found:
var keysToModify = this.Properties
.Where(k => k.Key == propertyName)
.ToList();
foreach (var key in keysToModify)
{
this.Properties[key] = newValue;
}
But my key field is a string not an int. What would I need to do to update a KeyValuePair in this case?
EDIT : My KeyValuePair is of type string,string, and when I run the code in my example above, I get the error :
keyvaluepair is not assignable to parameter type int
There is no particular magic to updating the value of the pair when the key is a string - it's much the same, you're just using a string to access a value (and this stands for any type being used as key, omitting any possible peculiarities).
But the only thing I can think might be throwing you off in this case is the loop. The loop is iterating instances, though, and isn't exposing an additive "index" in doing so, but rather key in this case would be a string.
The key wasn't an integer in your linked question either, it was a Customer.
You should be able to use the same general method no matter what the key type is.
Here's example code like the accepted answer to the other question that will work when the key is a string:
// The ToList() call here is important, so that we evaluate all of the query
// *before* we start modifying the dictionary
var keysToModify = CustomerOrderDictionary.Keys
.Where(k => k == "MyString")
.ToList();
foreach (var key in keysToModify)
{
CustomerOrderDictionary[key] = 4;
}
Note that where the other answer accessed the Id property of the Customer key, you can directly compare the key to your target string.
Also, note that if you are just updating a single entry in the dictionary you don't need a loop, you can just do it directly. If you know the dictionary dictionary has an entry with the given key, or don't mind creating a new entry, just use:
CustomerOrderDictionary["MyString"] = 4;
or, to guard against creating new entry:
if (CustomerOrderDicionary.ContainsKey("MyString"))
{
CustomerOrderDictionary["MyString"] = 4;
}
I'm trying to write a neat little generic Sql method that will accept a SQL Query and a list of parameters, and return a result. I want to keep it neat enough that I can call it using one line from any other code.
Is there any really awesomely neat way of doing this? I don't want to create all the SqlParameters in the calling code, and I don't want to have to pass and split a string. In the past I've used a string[] array and accepted every odd member as a parameter name and every even as a param value but that's too easy to screw up when calling the method.
Ideally I'd love to do just this:
Data.SQL("Select * from Table where my_id = #my_id", { my_id = 1 });
I know that's a little unrealistic, So I tried this:
Data.SQL("Select * from Table where my_id = #my_id", new Object[,]{ { "my_id", 1 } });
However when I try and handle that on the other end, I get nothing but trouble:
public static Object SQL(String command, Object[,] parameters = null){
[ ... reusable SQL code here... ]
foreach(Object[] p in parameters){
cmd.Parameters.Add(new SqlParameter(p[0].ToString(), p[1].ToString());
}
}
Looks fine, but throws an error on the foreach statement
foreach (Object[] p in parameters)
Unable to cast object of type 'System.String' to type 'System.Object[]'
But I didn't pass it an array of System.String. What I passed was a 2D System.Object[]! Wasn't it?
Maybe this is just some small code problem, something stupid I'm doing wrong. It usually is. But I'm figuring you guys know some even neater way to do the above.
Ideally I'd love to do just this:
Data.SQL("Select * from Table where my_id = #my_id", { my_id = 1 });
I know that's a little unrealistic,
Well, in exactly that form, yes... but try this instead:
Data.SQL("Select * from Table where my_id = #my_id", new { my_id = 1 });
That will use an anonymous type for the argument, which you can examine by reflection. You probably only need a single parameter (i.e. it would be SQL(string sql, object parameters)) because you would pass multiple parameters in a single object:
Data.SQL("Select * from Table where my_id = #my_id and name = #name",
new { my_id = 1, name = "Jon" });
More alternatives:
If you're using C# 4, you might find dynamic typing useful; look at what Massive does for example.
As mentioned by Ray, you could pass in a Dictionary<string, object>; again, C# 3 makes this easier than otherwise:
Data.SQL("...", new Dictionary<string, object> {
{ "my_id", 1 },
{ "name", "Jon" }});
EDIT: As for the exact problem you're running into: you need to understand the difference between a rectangular array (e.g. Object[,]) and a jagged array (e.g. Object[][]). The latter is an array of arrays, which is how you're trying to use the parameter, but it's really only a rectangular array. Changing your parameter type to Object[][] may well fix that immediate problem - but personally I'd move to one of the approaches above. I'd also try to avoid making everything into a string, by the way.