XUnit Using a Dictionary As MemberData - c#

I am having trouble with the syntax of how to get an XUnit Test Method to accept a dictionary as a paramater. This is my code which is broken:
Public static Dictionary<string, string> vals = new Dictionary<string, string> { { "a", "1" }, { "b", "2" }, { "ca", "3" } };
public static object[] dicList = new object[] { vals };
[Theory]
[MemberData(nameof(dicList))]
public void CheckSomething_ReturnsSomething(Dictionary<string, string> values)
{
test stuff...
I am getting an error I understand from the error thrown that I need a return type of
IEnumerable<object[]>
I am unsure of how to achieve this with a dictionary.
Have added some code as suggested: I am still getting an error:
public static Dictionary<string, string> vals = new Dictionary<string, string> { { "a", "1" }, { "b", "2" }, { "ca", "3" } };
public static IEnumerable<object[]> dicList = new List<object[]> { new object[] { vals } };
[Theory]
[MemberData(dicList)] //error here
public void DriverLogon_CheckParams(Dictionary<string, string> values)
{
}
The new error is
error. "Cannot convert from IEnumerable<object[]> To string

The dicList must be an IEnumerable<object[]> like the error message says. This is because one item in the dicList contains all the parameter values for one test (this doesn't matter for your case since you only have one parameter, but it's good to know).
So your dicList becomes a List<object[]> instead of just plain object array:
public static Dictionary<string, string> vals = new Dictionary<string, string> { { "a", "1" }, { "b", "2" }, { "ca", "3" } };
public static IEnumerable<object[]> dicList = new List<object[]> { new object[] { vals } };

Related

How to merge two List<dynamic> objects into one with specific condition in C#?

List object1
[ { "empId":10001, "empName":"test1" }, { "empId":10002, "empName":"test2" } ]
List object2
[ { "empId":10001, "emailAddress":"test1#mail.com" }, { "empId":10002, "emailAddress":"test2#mail.com" } ]
Trying to get the merge result which matches "empId" in both objects.
Result
[
{
"empId":10001,
"empName":"test1",
"emailAddress":"test1#mail.com"
},
{
"empId":10002,
"empName":"test2",
"emailAddress":"test2#mail.com"
}
]
I have tried https://www.newtonsoft.com/json/help/html/MergeJson.htm. but not able to do the matching logic "empId"
Here is some code that will Join and Merge, working here.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Dynamic;
using System.Linq;
using Newtonsoft.Json;
public class Program
{
public static void Main()
{
var list1 = new[]
{
new { empId = 10001, empName = "test1" },
new { empId = 10002, empName = "test2" }
};
var list2 = new[]
{
new { empId = 10001, emailAddress = "test1#mail.com" },
new { empId = 10002, emailAddress = "test2#mail.com" }
};
var results1 = list1.MergeJoin(list2, e => e.empId);
Console.WriteLine($"{nameof(results1)}:");
Console.WriteLine(JsonConvert.SerializeObject(results1, Formatting.Indented));
Console.WriteLine();
IList<dynamic> dynamicList1 = new List<dynamic>
{
new { empId = 10001, empName = "test1", utterance = "wibble" },
new { empId = 10002, empName = "test2", expression = "bemused" }
};
IList<dynamic> dynamicList2 = new List<dynamic>
{
new { empId = 10001, emailAddress = "test1#mail.com", IQ = "moron" },
new { empId = 10002, emailAddress = "test2#mail.com", smell = "cheesy" }
};
var results2 = dynamicList1.MergeJoin(dynamicList2, e => e.empId);
Console.WriteLine($"{nameof(results2)}:");
Console.WriteLine(JsonConvert.SerializeObject(results2, Formatting.Indented));
}
}
public static class Extensions
{
public static IEnumerable<dynamic> MergeJoin<TKey>(
this IEnumerable<dynamic> outer,
IEnumerable<dynamic> inner,
Func<dynamic, TKey> keyAccessor)
{
return outer.Join(
inner,
keyAccessor,
keyAccessor,
Merge);
}
public static dynamic Merge(dynamic left, dynamic right)
{
IDictionary<string, object> dictionary1 = GetKeyValueMap(left);
IDictionary<string, object> dictionary2 = GetKeyValueMap(right);
var result = new ExpandoObject();
var d = result as IDictionary<string, object>;
foreach (var pair in dictionary1.Concat(dictionary2))
{
d[pair.Key] = pair.Value;
}
return result;
}
private static IDictionary<string, object> GetKeyValueMap(object values)
{
if (values == null)
{
return new Dictionary<string, object>();
}
var map = values as IDictionary<string, object>;
if (map != null)
{
return map;
}
map = new Dictionary<string, object>();
foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(values))
{
map.Add(descriptor.Name, descriptor.GetValue(values));
}
return map;
}
}
This should output,
results1:
[
{
"empId": 10001,
"empName": "test1",
"emailAddress": "test1#mail.com"
},
{
"empId": 10002,
"empName": "test2",
"emailAddress": "test2#mail.com"
}
]
results2:
[
{
"empId": 10001,
"empName": "test1",
"utterance": "wibble",
"emailAddress": "test1#mail.com",
"IQ": "moron"
},
{
"empId": 10002,
"empName": "test2",
"expression": "bemused",
"emailAddress": "test2#mail.com",
"smell": "cheesy"
}
]
The Merge() function you are using is not the only thing you need. You need LINQ's Join() to "merge" the two lists and then Merge() to merge individual items:
var xs = JArray
.Parse(#"[
{""empId"": 10001, ""empName"": ""test1""},
{""empId"": 10002, ""empName"": ""test2""}
]")
.Values<JObject>();
var ys = JArray
.Parse(#"[
{""empId"": 10001, ""emailAddress"": ""test1#mail.com""},
{""empId"": 10002, ""emailAddress"": ""test2#mail.com""}
]")
.Values<JObject>();
var merged = xs.Join(
ys,
x => x["empId"],
y => y["empId"],
(x, y) => { x.Merge(y); return x; });
Note that you can probably just cast the dynamic types back to JObject for much easier handling.

How to create custom serializer for values in dictionary?

I have the following class:
public class Farm
{
public string County {get;set;}
public Dictionary<string, object> FarmItems {get;set;}
}
I need to implement a custom serializer/deserializer that, if it's a integer in the value, store it in the DB as a string and then deserialize it back to a integer
I've looked at the docs and they gave details on how to do it for single values but not for dictionaries https://mongodb.github.io/mongo-csharp-driver/2.12/reference/bson/serialization/
Also, the docs don't mention how to implement it, do I just add an attribute after creating my class like so:
[BsonSerializer(typeof(MyCustomSerializer))]
public Dictionary<string, object> FarmItems {get;set;}
here you go:
public class MyDictionarySerialzer : SerializerBase<Dictionary<string, object>>
{
public override void Serialize(BsonSerializationContext ctx, BsonSerializationArgs args, Dictionary<string, object> dictionary)
{
if (dictionary == null)
{
ctx.Writer.WriteStartArray();
ctx.Writer.WriteEndArray();
return;
}
ctx.Writer.WriteStartArray();
foreach (var kvPair in dictionary)
{
ctx.Writer.WriteStartDocument();
ctx.Writer.WriteName("k");
ctx.Writer.WriteString(kvPair.Key);
ctx.Writer.WriteName("v");
if (kvPair.Value is int)
ctx.Writer.WriteString(kvPair.Value.ToString());
else
BsonSerializer.Serialize(ctx.Writer, kvPair.Value);
ctx.Writer.WriteEndDocument();
}
ctx.Writer.WriteEndArray();
}
public override Dictionary<string, object> Deserialize(BsonDeserializationContext ctx, BsonDeserializationArgs args)
{
Dictionary<string, object> dict = new();
switch (ctx.Reader.CurrentBsonType)
{
case BsonType.Array:
foreach (var val in BsonSerializer.Deserialize<BsonArray>(ctx.Reader))
{
string key = val["k"].AsString;
object value = BsonSerializer.Deserialize<object>(val["v"].ToJson());
if (int.TryParse(value?.ToString(), out var parsedInt))
value = parsedInt;
dict.Add(key, value);
}
return dict;
default:
throw new BsonSerializationException("Unable to deserialize dictionary!");
}
}
}
if you are storing any complex entities in the dictionary values, you have to register (on app startup) that complex type with mongo driver like so (or deserialization will fail):
BsonClassMap.RegisterClassMap<ComplexItem>();
simply decorate the property like so:
public class Farm
{
[BsonSerializer(typeof(MyDictionarySerialzer))]
public Dictionary<string, object> FarmItems { get; set; }
}
example entity:
var example = new Farm
{
FarmItems = new Dictionary<string, object>()
{
{"empty",null },
{"string","test string" },
{"int",100 },
{"complex",new ComplexItem{ Age = 10, Name = "test" } }
}
};
it will be serialized to the db like so:
{
"FarmItems" : [
{
"k" : "empty",
"v" : null
},
{
"k" : "string",
"v" : "test string"
},
{
"k" : "int",
"v" : "100"
},
{
"k" : "complex",
"v" : {
"_t" : "ComplexItem",
"Name" : "test",
"Age" : 10
}
}
]
}

Pretty printing a collection recursively

I've seen lots of questions about this, but I haven't seen any about doing it recursively. I've created some extension methods that do a pretty good job of pretty printing at a depth of 1. It looks like this:
public static string PrettyToString<K, V>(this Dictionary<K, V> dictionary)
{
string result = "{";
foreach (var kvp in dictionary)
{
result += $"({kvp.Key}, {kvp.Value}) ";
}
result += "}";
return result;
}
public static string PrettyToString<T>(this List<T> list)
{
string result = "{";
foreach (var element in list)
{
result += $"{element}, ";
}
result += "}";
return result;
}
public static string PrettyToString<T>(this T [] list)
{
string result = "{";
foreach (var element in list)
{
result += $"{element}, ";
}
result += "}";
return result;
}
But, what if K, V, or T is another collection like a List or a Dictionary? I want to recursively pretty print, but I'm not sure how to do that. As a result, my output looks like this:
{(foo, System.Collections.Generic.Dictionary`2[System.String,System.Boolean])...
I want it to look like this instead:
{(foo, {(bar, true)})...
I'm looking for methods that print recursively regardless of the nested types:
var x = new List<Dictionary<string, string>>();
var y = new Dictionary<Dictionary<string, string>, string>>();
var z = new Dictionary<Dictionary<string, string>, List<string>>>();
...
x.PrettyToString();
y.PrettyToString();
z.PrettyToString();
Should all recursively print out the contents. How do I achieve that?
I changed the signature of your methods and made them non-generic.
The trick is to determine the type before converting.
Look at the sample code below. I hope it helps.
Please look at the Ext class at the bottom of the source code.
Try it online
using System;
using System.Collections;
using System.Collections.Generic;
namespace ConsoleApp8
{
class Program
{
static void Main(string[] args)
{
var Dic = new Dictionary<int, string> { { 1, "Ali" }, { 2, "B" } };
Console.WriteLine(Dic.PrettyToString());
var Dic1 = new Dictionary<string, float> { { "Ali", 12.5f }, { "B", 99.9f } };
Console.WriteLine(Dic1.PrettyToString());
var Dic2 = new Dictionary<List<int>, string>
{
{ new List<int> { 1, 2, 3 }, "A" },
{ new List<int> { 4, 5, 6 }, "B" }
};
Console.WriteLine(Dic2.PrettyToString());
var Dic3 = new Dictionary<Dictionary<string, string>, string>
{
{ new Dictionary<string, string> { { "a", "A" }, { "b", "B" } }, "Capital" },
{ new Dictionary<string, string> { { "1", "1" }, { "2", "4" }, { "4", "16" } }, "Power" }
};
Console.WriteLine(Dic3.PrettyToString());
var Dic4 = new Dictionary<Dictionary<string, string>, List<string>>
{
{ new Dictionary<string, string> { { "a", "A" }, { "b", "B" } }, new List<string> { "A", "B" } },
{ new Dictionary<string, string> { { "1", "1" }, { "2", "4" }, { "4", "16" } }, new List<string> { "1", "2", "4" } }
};
Console.WriteLine(Dic4.PrettyToString());
var L = new List<List<int>>
{
new List<int> { 1, 2, 3 },
new List<int> { 4, 5, 6 }
};
Console.WriteLine(L.PrettyToString());
Console.ReadKey();
}
}
static class Ext
{
public static string PrettyToString(this IDictionary dictionary)
{
string result = "{";
foreach (var Key in dictionary.Keys)
{
result += string.Format("({0}, {1}) ", PrettyToString(Key), PrettyToString(dictionary[Key]));
}
result += "}";
return result;
}
public static string PrettyToString(this IEnumerable list)
{
string result = "{";
foreach (var element in list)
{
result += string.Format("{0}, ", PrettyToString(element));
}
result += "}";
return result;
}
private static string PrettyToString(object O)
{
var S = O as string;
if (S != null) return S;
var D = O as IDictionary;
if (D != null) return D.PrettyToString();
var L = O as IEnumerable;
if (L != null) return L.PrettyToString();
return O.ToString();
}
}
}

How To Create a Dictionary Tree in C#

I have the following code:
class Foo<KType, VType>
{
public KType Key;
public VType Value;
public List<Foo<KType, VType>> Children;
}
class Test
{
public Test()
{
var x = new List<Foo<int, string>>()
{
new Foo<int, string>() {Key = 1, Value = "a", Children = new List<Foo<int, string>>()
{
new Foo<int, string>() {Key = 1, Value = "a"},
new Foo<int, string>() {Key = 2, Value = "b"}
}
},
new Foo<int, string>() {Key = 2, Value = "b"}
};
}
}
It works beautifully in allowing me to have a tree of nested "pairs" of {KType, VType}. However, because I have a List and not a Dictionary, I don't have a way of enforcing that the keys will be unique. How can I construct a tree or chain of dictionaries or the equivalent? I'd like to change the underlying type of "Children" to a dictionary, but that takes a KeyValuePair, which takes only 2 items, a key and a value, and there'd be no room for the grandchildren.
As mentioned by #jdweng, the dictionary could map keys to foos:
class Foo<KType, VType>
{
public VType Value;
public Dictionary<KType, Foo<KType, VType>> Children;
}
class Test
{
public Test()
{
var root = new Foo<int, string>
{
Value = "root",
Children = new Dictionary<int, Foo<int, string>>
{
{
1,
new Foo<int, string>
{
Value = "a",
Children = new Dictionary<int, Foo<int, string>>
{
{1, new Foo<int, string> {Value = "a", Children = null}},
{2, new Foo<int, string> {Value = "b", Children = null}}
}
}
},
{
2,
new Foo<int, string>
{
Value = "b",
Children = null
}
}
}
};
}
}

Initialize Dictionary<string, List<string>>

I would like to know how do I declare/initialize a dictionary ?
The below one gives error.
Dictionary<string, List<string>> myD = new Dictionary<string, List<string>>()
{
{"tab1", MyList }
};
List <string> MyList = new List<string>() { "1" };
The error is: A field initializer cannot reference the non-static field, method, or property MyList. It is not List declaration coming in front or later after dictionary.
class MyClass
{
Dictionary<string, List<string>> myD = new Dictionary<string, List<string>>()
{
{"tab1", new List<string> { "1" } },
{"tab2", new List<string> { "1","2","3" } },
{"tab3", new List<string> { "one","two" } }
};
}
As Scott Chamberlain said in his answer:
If these are non static field definitions you can not use the field
initializers like that, you must put the data in the constructor.
class MyClass
{
Dictionary<string, List<string>> myD;
List <string> MyList;
public MyClass()
{
MyList = new List<string>() { "1" };
myD = new Dictionary<string, List<string>>()
{
{"tab1", MyList }
};
}
}
Additionally for Static field
private static List<string> MyList = new List<string>()
{
"1"
};
private static Dictionary<string, List<string>> myD = new Dictionary<string, List<string>>()
{
{"tab1", MyList }
};
If these are non static field definitions you can not use the field initializers like that, you must put the data in the constructor.
class MyClass
{
Dictionary<string, List<string>> myD;
List <string> MyList;
public MyClass()
{
MyList = new List<string>() { "1" };
myD = new Dictionary<string, List<string>>()
{
{"tab1", MyList }
};
}
}

Categories

Resources