Strange behavior of C# Dictionary - c#

I have following simplified program
using System;
using System.Collections.Generic;
using System.Text;
class ItemClass {
public int Id = 0;
public int[] Childs = new int[] { };
public int Count = 0;
}
class Class1 {
Dictionary<int, ItemClass> _Items = new Dictionary<int, ItemClass> { };
private void AddRecursive(int ItemID, int count, ref Dictionary<int, ItemClass> ItemList) {
if (!_Items.ContainsKey(ItemID)) {
return;
}
ItemClass _item = _Items[ItemID];
if (!ItemList.ContainsKey(ItemID)) {
ItemList.Add(ItemID, _item);
}
ItemList[ItemID].Count += count;
if (_item.Childs.Length > 0) {
foreach (int tmpItem in _item.Childs) {
AddRecursive(tmpItem, ItemList[ItemID].Count, ref ItemList);
}
}
}
public void Add(int item, int[] childs) {
if (!_Items.ContainsKey(item)) {
_Items.Add(item, new ItemClass() { Id = item, Childs = childs, Count = 0 });
}
}
public Dictionary<int, ItemClass> MakeList(int ItemID) {
if (!_Items.ContainsKey(ItemID)) {
return new Dictionary<int, ItemClass> { };
}
Dictionary<int, ItemClass> ItemList = new Dictionary<int, ItemClass> { };
AddRecursive(ItemID, 1, ref ItemList);
return ItemList;
}
}
class Program {
static void Main(string[] args) {
Class1 class1 = new Class1();
class1.Add(1111, new int[] { });
class1.Add(2222, new int[] { 1111 });
class1.Add(3333, new int[] { 1111, 2222 });
Dictionary<int, ItemClass> items1 = class1.MakeList(3333);
foreach (ItemClass item in items1.Values) {
Console.WriteLine(item.Id + " " + item.Count);
}
Console.WriteLine("");
Dictionary<int, ItemClass> items2 = class1.MakeList(3333);
foreach (ItemClass item in items2.Values) {
Console.WriteLine(item.Id + " " + item.Count);
}
Console.ReadKey();
}
}
It has a simple task of counting items and showing a list of items and their count. When I call the MakeList function the first time, results are expected.
Expected:
3333 1
1111 2
2222 1
3333 1
1111 2
2222 1
Actual
3333 1
1111 2
2222 1
3333 2
1111 7
2222 3
As I am re-declaring the variable ItemList, I'm expecting to see the same result when I call the function for second time, however it is like the results from previous call is cached and re-used.
Why this is happening and why is this behavior?
Is there any way to avoid it?

Actually there is nothing strange with it. You've just modified the value of Count property in your ItemClass object when you call AddRecursive method.
Assuming that you really want to get what you expected, you just need to deep clone your ItemClass object or simply create new instance and copy the original value of property.
ItemClass _item = new ItemClass() { Childs = _Items[ItemID].Childs, Count = _Items[ItemID].Count, Id = _Items[ItemID].Id };
Instead of this
Itemclass _item = _Items[ItemId]

You re-declaring ItemList, but using same objects from internal _Items : ItemClass _item = _Items[ItemID]; and incrementing count on same object. It is why part :). avoid part is to create new items maybe.

Your problem is that you alter the Count property of the ItemClass instances in the _Items dictionary while you run AddRecursive.
Get rid of that mutable Count property (it really shouldn't be in ItemClass), and simplify your code to
class ItemClass
{
public int Id = 0;
public int[] Childs = new int[] { };
}
class Class1
{
Dictionary<int, ItemClass> _Items = new Dictionary<int, ItemClass>();
private void AddRecursive(int itemId, Dictionary<int, int> itemList)
{
if (!_Items.ContainsKey(itemId))
return;
if (!itemList.ContainsKey(itemId))
itemList.Add(itemId, 1);
else
itemList[itemId] += 1;
var item = _Items[itemId];
if (item.Childs.Length > 0)
foreach (int tmpItem in item.Childs)
AddRecursive(tmpItem, itemList);
}
public void Add(int item, int[] childs)
{
if (!_Items.ContainsKey(item))
_Items.Add(item, new ItemClass() { Id = item, Childs = childs });
}
public Dictionary<int, int> MakeList(int itemId)
{
if (!_Items.ContainsKey(itemId))
return new Dictionary<int, int>();
var itemList = new Dictionary<int, int>();
AddRecursive(itemId, itemList);
return itemList;
}
}

Related

how to BinarySearch in condition?

I have here this code to create ID Randome when calling and then add to the ArrayList, but I want to check if I already have same ID to dont added to ArrayList I have used BinarySearch to check Result
but it look there Something wrong
public delegate void DESetUp();
public static DESetUp IdSetUP = delegate ()
{
ArrayList valID = new ArrayList();
Func<int> getID = () => new Random().Next(1, 5);
int Result = getID();
if (Result == valID.BinarySearch(Result))
{
valID.Add(Result);
Console.WriteLine("AddSuccessful");
}
else
{
Console.WriteLine("AddFailed");
}
foreach (var item in valID)
{
Console.WriteLine("your id is : {0}", item);
}
};
Thank you
try this:
use List instead of ArrayList:
Always you need to sort the values with BinarySearch
List<int> valID = new List<int>();
Func<int> getID = () => new Random().Next(1, 10);
int Result = getID();
// here need to sort the list
valID.Sort();
if (valID.BinarySearch(Result) < 0) // if the position of value is lles than zero the value does not exists
{
valID.Add(Result);
Console.WriteLine("AddSuccessful");
}
else
{
Console.WriteLine("AddFailed");
}
i have reached a great result
i have assisted delegate List
public class MainClass
{
//assist delegate List<int>
public delegate void DESetUp(List<int> DLint);
//assist delegate List<int>
public static DESetUp IdSetUP = delegate (List<int> valID)
{
Func<int> getID = () => new Random().Next(1, 3);
int Result = getID();
// here need to sort the list
valID.Sort();
if (valID.BinarySearch(Result) < 0) // if the position of value is lles than zero the value does not exists
{
valID.Add(Result);
Console.WriteLine("AddSuccessful");
}
else
{
Console.WriteLine("AddFailed");
}
foreach (int item in valID)
{
Console.WriteLine(item);
}
};
static void Main(string[] args)
{
//assist List<int> ID
List<int> ID = new List<int>();
//ADD delegate + List<int> + IdSetUP
IdSetUP(ID);
IdSetUP(ID);
IdSetUP(ID);
IdSetUP(ID);
}
}
thank you all

How to create a List variable that can contain array of int or string in C#?

How to create a List variable that can contain array of int or string in C#?
I have a class:
public class GoogleAdSlot
{
public IList<int[]> Size { get; set; }
}
How do I create a List such that
return new GoogleAdData
{
AdSlots = new Dictionary<string, GoogleAdSlot>
{
{
"googleAdSquareTile1",
new GoogleAdSlot {
Size = new List<int[]>
{
new[] {250, 250},
new[] {300, 300},
}
}
}
}
};
And:
return new GoogleAdData
{
AdSlots = new Dictionary<string, GoogleAdSlot>
{
{
"googleAdSquareTile1",
new GoogleAdSlot {
Size = new List<int[]>
{
new[] {fluid},
}
}
}
}
};
are both valid.
sample here
List<object> lst = new List<object>() { "12",1,"apple"};
lst.ForEach(m => { Console.WriteLine((m is int) ? "int Varible" : "String Varibale"); });
You can only store one Type and its derived types in a generic List, in the case you described you would have to use List<object> or it's non generic counterpart ArrayList, but non-generic collections are not recommended and don't support newer features like LINQ.
So that would look something like:
var list = new List<object> {"lol", 101};
foreach (var value in list)
{
if(value is string s)
Console.WriteLine(s);
if (value is int i)
Console.WriteLine(i);
}
I'm still not sure exactly what your requirements are, but here's a solution for the most general case.
First
Create a class capable of holding a collection of either integers or strings (but not both). Note that it uses the Collection initialization pattern (twice) (see https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/object-and-collection-initializers)
Note that the various GetEnumerator implementations are there only to satisfy the collection initialization pattern. They throw if called, the expectation is that a consumer would call GetIntegerSizes or GetStringSizes.
Here's the code:
public class AdSlotSizes : IEnumerable<int>, IEnumerable<string>
{
public enum CollectionType
{
Uninitialized,
Integers,
Strings,
}
private List<int> _integerSizes;
private List<string> _stringSizes;
public void Add(int sizeToAdd)
{
InitializeList(CollectionType.Integers);
_integerSizes.Add(sizeToAdd);
}
public void Add(string sizeToAdd)
{
InitializeList(CollectionType.Strings);
_stringSizes.Add(sizeToAdd);
}
public CollectionType SizesCollectionType => _collectionType;
private CollectionType _collectionType = CollectionType.Uninitialized;
private void InitializeList(CollectionType forCollectionType)
{
CollectionType oppositeCollectionType = (CollectionType)(((int) CollectionType.Strings + 1) - (int) forCollectionType);
if (_collectionType == oppositeCollectionType)
{
throw new ArgumentException($"A single {nameof(AdSlotSizes)} instance can only hold one type of sizes (int or string)");
}
if (_collectionType != CollectionType.Uninitialized)
{
return;
}
_collectionType = forCollectionType;
if (forCollectionType == CollectionType.Strings)
{
_stringSizes = _stringSizes ?? new List<string>();
}
if (forCollectionType == CollectionType.Integers)
{
_integerSizes = _integerSizes ?? new List<int>();
}
}
public IEnumerable<int> GetIntegerSizes()
{
if (_collectionType != CollectionType.Integers)
{
throw new ArgumentException("Size collection not initialized for integers");
}
foreach (var size in _integerSizes)
{
yield return size;
}
}
public IEnumerable<string> GetStringSizes()
{
if (_collectionType != CollectionType.Strings)
{
throw new ArgumentException("Size collection not initialized for strings");
}
foreach (var size in _stringSizes)
{
yield return size;
}
}
IEnumerator<string> IEnumerable<string>.GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator<int> IEnumerable<int>.GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
}
Second
Now I create a class that collections AdSlotSizes instances (again, using the collection initialization pattern). It also implements an indexed property (public AdSlotSizes this[int index]), allowing the consumer to index into the collection:
public class GoogleAddSlot : IEnumerable<AdSlotSizes>
{
private readonly List<AdSlotSizes> _slotSizes = new List<AdSlotSizes>();
public void Add(AdSlotSizes sizes)
{
_slotSizes.Add(sizes);
}
public AdSlotSizes this[int index] => _slotSizes[index];
public IEnumerator<AdSlotSizes> GetEnumerator()
{
foreach (var sizes in _slotSizes)
{
yield return sizes;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return (IEnumerator < AdSlotSizes > )this.GetEnumerator();
}
}
Finally, a test method:
public static void TestCollectionSizes()
{
var slot = new GoogleAddSlot
{
{new AdSlotSizes {200, 300, 400} },
{new AdSlotSizes {"fluid", "solid"}},
};
foreach (int size in slot[0].GetIntegerSizes())
{
Debug.WriteLine($"Integer Size: {size}");
}
foreach (string size in slot[1].GetStringSizes())
{
Debug.WriteLine($"String Size: {size}");
}
}
When run, this test method outputs:
Integer Size: 200
Integer Size: 300
Integer Size: 400
String Size: fluid
String Size: solid

Linq Expression snaphot an index value

This problem is easiest described with code:
class Program
{
static void Main(string[] args)
{
int index = 0;
var listOfExpressions = new List<ClassHoldingExpression>();
listOfExpressions.Add(new ClassHoldingExpression((a) => a.Dict[index]));
index++;
listOfExpressions.Add(new ClassHoldingExpression((a) => a.Dict[index]));
var dictClass = new ClassWithDict();
dictClass.Dict[0] = "Test 1";
dictClass.Dict[1] = "Test 2";
foreach (var expr in listOfExpressions)
Console.WriteLine((string)expr.Eval(dictClass));
}
}
public class ClassWithDict
{
public ClassWithDict()
{
Dict = new Dictionary<int, object>();
}
public Dictionary<int, object> Dict { get; set; }
}
public class ClassHoldingExpression
{
private Expression<Func<ClassWithDict, object>> Expression { get; set; }
public ClassHoldingExpression(Expression<Func<ClassWithDict, object>> expr)
{
Expression = expr;
}
public object Eval(ClassWithDict source)
{
return this.Expression.Compile().Invoke(source);
}
}
//Output:
//Test 2
//Test 2
//Desired:
//Test 1
//Test 2
Basically, I want to populate that dictionary with multiple values, and populate the list of ClassHoldingExpression with different expressions at specific indeces. However, it seems to look back and look for the current value of "index", instead of saving the current value into the expression. How can I force it to save the current value of index into the Expression?
You will have to create a new variable that will hold the value that you want.
int index0 = 0;
var listOfExpressions = new List<ClassHoldingExpression>();
listOfExpressions.Add(new ClassHoldingExpression((a) => a.Dict[index0]));
int index1 = index0 + 1;
listOfExpressions.Add(new ClassHoldingExpression((a) => a.Dict[index1]));
If you need to do that in a loop, define a variable for each loop iteration before capturing it.
looks like a closure issue.
foreach (var TMPexpr in listOfExpressions){
var expr = TMPexpr ; // take LOCAL copy
Console.WriteLine((string)expr.Eval(dictClass));
}
similar SO post

Getting nth property of a class

Am a beginner in C# language
I have a class like
public class Plan
{
int a;
int b;
int c;
}
Can in any way I get the nth property of the class.
for eg: planObject.propertyIndex
This would be of great help for my project, as I am getting index number denoting the property whose value is to be changed. What I am doing right now is using if...else .
if(index ==1)
{
planObject.a = 100;
}
else if(index ==2)
{
planObject.b = 100;
}
Is there any other solution for this by using reflection?
You could use reflection, however, i would strongly advise against. Instead use a collection like List<int> or int[]. In this case, since you want to get the nth int value, you could also use a Dictionary<int, int>:
public class Plan
{
Dictionary<int, int> Values;
public Plan()
{
Values = new Dictionary<int, int>();
Values.Add(1, 100);
Values.Add(2, 200);
Values.Add(3, 300);
}
// ...
}
Now you can access the value by the number:
int value = Values[1]; // 100
Here's a list version:
public class Plan
{
List<int> Values = new List<int>();
public Plan()
{
Values.Add(100);
Values.Add(200);
Values.Add(300);
}
// ...
}
You access it via (zero based) index:
int value = Values[0]; // 100
A word of WARNING, this is in no way for beginners at all. And it might just make the code more complex. This answer takes for granted that you have a working knowledge of extension methods and reflection.
public static class PlanExtension
{
PropertyInfo _info = typeof(Plan).GetProperties();
public static void SetValue(this Plan plan, int index, int value)
{
var prop = _info[index - 1]; // So 1 maps to 0.. or 1 in this case
prop.SetValue(plan, value, null);
}
public static int GetValue(this Plan plan, int index)
{
var prop = _info[index - 1]; // Mapping magic
return (int) prop.GetValue(plan, null);
}
}
Called like this:
var p = new Plan();
p.SetValue(1, 139); // "a"
var b = p.GetValue(2); // "b"
It would help if you had a definable order to the properties, like name or something. Also, error handling is a must when it comes to reflection.
There's no "property by index" feature, but one approach that would make consumption easier would be to build an indexer on the class and encapsulate the switch statement there. Maybe something like this:
public class Plan
{
public int this[int index]
{
get
{
switch (index)
{
case 1:
return this.a;
...
}
}
set
{
switch (index)
{
case 1:
this.a = value;
...
}
}
}
}
So, now using it looks like this:
planObject[i] = 100;
Now, in your case it looks like you have an additional need because you have a key (the index) and a value (e.g. 100), so you need to store your keys and values in a Dictionary. So, in your class that uses Plan create a private field:
private Dictionary<int, int> _values = new Dictionary<int, int>
{
{ 1, 100 },
{ 2, 200 },
...
}
To use the dictionary you'd do something like this:
planObject[i] = _values[i];
UPDATE: if you can't change the class Plan then you'll need to do something like this. First you need a map from index to property name:
private Dictionary<int, string> _properties = new Dictionary<int, string>
{
{ 1, "a" },
{ 2, "b" },
...
}
and next you'll need to set that property:
var t = planObject.GetType();
var p = t.GetProperty(_properties[i]);
if (p != null)
{
p.SetValue(planObject, 100);
}
If you must use the object, instead of suggested Collections.
Plan b = new Plan();
Type t = new Type(b.GetType());
var properties = t.GetProperties();
for(int index = 0; index < properties.Length; index++)
{
properties[index].SetValue(b, 100);
}
Instead of using loop, you can pass your own index in properties array.
I hope it helps.
Here is what you want
public class Foo
{
public int A {get;set;}
public string B {get;set;}
public object GetPropertyValueAt(int index)
{
var prop = this.GetType().GetProperties()[index];
return prop.GetValue(this, null);
}
}
Usage
Foo foo = new Foo() {A = 1, B = "abc"};
int valueA = (int)foo.GetPropertyValueAt(0);
string valueB = (string)foo.GetPropertyValueAt(1);
int valueUnknown = (int)foo.GetPropertyValueAt(2); //<--- this line will give you an exception.

Select new {Unknown fields} from IEnumerable<UnknownType>

I am using VS2010 and EF4.0. The goal is to select fields of any IEnumerable, in order to show in the DataGridView. Take Northwind.Employees as example, the following code is OK.
private void button1_Click(object sender, EventArgs e)
{
NorthwindEntities en = new NorthwindEntities();
dataGridView1.DataSource = SelectNew(en.Employees, new string[] { "EmployeeID", "FirstName" });
}
public object SelectNew(object items, string[] fields)
{
IEnumerable<Employee> ems = items as IEnumerable<Employee>;
return ems.Select(em => new
{
id = em.EmployeeID,
name = em.FirstName
}
).ToArray();
}
The parameter object items is IEnumerable of EntityObject, and the function will be executed at client side memorry and shall have nothing to do with database now.
But I don't know the EntityObject type (Employee) until runtime, so maybe some complex reflection will be used.
I have checked this,
but when I bind the result to the control, it showed only blank rows without any column or data. And the funciton is for IQueryable, I have tried IEnumerable.AsQueryable and pass to it, but the results did not show any column either.
I've modified the example I pointed to in my comment above. This actually returns an IEnumerable<Dictionary<string,object>>, where each Dictionary represents one of the "new objects", and each key value pair in the dictionary represents a property and its value. Perhaps you can modify this for your use?
I'm not sure if you can simply bind the result to the DataGrid, but you should be able to figure it out.
I don't believe it's possible to create an anonymous type on the fly... But it might be possible to change this to use a dynamic type like ExpandoObject instead of a Dictionary. See this question for some hints on how to do that. I've never used dynamic objects, so you're on your own there!
public class TestClassA {
public string SomeString { get; set; }
public int SomeInt { get; set; }
public TestClassB ClassB { get; set; }
}
public class TestClassB {
public string AnotherString { get; set; }
}
public class Program {
private static void Main(string[] args) {
var items = new List<TestClassA>();
for (int i = 0; i < 9; i++) {
items.Add(new TestClassA {
SomeString = string.Format("This is outer string {0}", i),
SomeInt = i,
ClassB = new TestClassB { AnotherString = string.Format("This is inner string {0}", i) }
});
}
var newEnumerable = SelectNew(items, new string[] { "ClassB.AnotherString" });
foreach (var dict in newEnumerable) {
foreach (var key in dict.Keys)
Console.WriteLine("{0}: {1}", key, dict[key]);
}
Console.ReadLine();
}
public static IEnumerable<Dictionary<string, object>> SelectNew<T>(IEnumerable<T> items, string[] fields) {
var newItems = new List<Dictionary<string, object>>();
foreach (var item in items) {
var dict = new Dictionary<string, object>();
foreach (var field in fields)
dict[field] = GetPropertyValue(field, item);
newItems.Add(dict);
}
return newItems;
}
private static object GetPropertyValue(string property, object o) {
if (property == null)
throw new ArgumentNullException("property");
if (o == null)
throw new ArgumentNullException("o");
Type type = o.GetType();
string[] propPath = property.Split('.');
var propInfo = type.GetProperty(propPath[0]);
if (propInfo == null)
throw new Exception(String.Format("Could not find property '{0}' on type {1}.", propPath[0], type.FullName));
object value = propInfo.GetValue(o, null);
if (propPath.Length > 1)
return GetPropertyValue(string.Join(".", propPath, 1, propPath.Length - 1), value);
else
return value;
}
}

Categories

Resources