I have the following json string:
[
{
"Key":"A",
"Value":null
},
{
"Key":"B",
"Value":"18"
},
{
"Key":"C",
"Value":"False"
},
{
"Key":"D",
"Value":"BOB"
}
]
I would like to be able to deserialize into the following objects:
public class ModelOne
{
public int? A { get; set; }
public int B { get; set;}
}
public class ModelTwo
{
public bool C { get; set; }
public string D { get; set; }
}
We thought about using var model = JsonConvert.DeserializeObject<ModelOne>(json); but clearly the json string is a list of Key and Value so that wouldn't work.
In an ideal world we would like to parse the json and match the Key to the Property Name and set the Value according to the property type. We could use a similar function to the above which accepts an anonymous type we're just not sure where to start so would be very greatful for some feedback and or assistance.
Thanks in advance.
EDIT:
The json array represents some data points we receive from an external api call.
ModelOne and ModelTwo are each view models in our MVC project we would like to pre-populate.
Thanks very much for all of your comments but notably both of #mjwills and #Heretic Monkey you really helped.
In the (end against my better judgement) I decided to use a little reflection.
public T ConvertDataMapToModel<T>(T item, List<Data> list)
{
Type itemType = typeof(T);
var response = (T)item;
var props = response.GetType().GetProperties();
foreach (var prop in props)
{
string propName = prop.Name;
string listValue = (string)(from c in list where c.Key == prop.Name select c.Value).FirstOrDefault();
if (!string.IsNullOrWhiteSpace(listValue) && !string.IsNullOrEmpty(listValue))
{
PropertyInfo pInstance = itemType.GetProperty(propName);
Type pInstancePropertyType = pInstance.PropertyType;
if (pInstancePropertyType.IsGenericType && pInstancePropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
pInstancePropertyType = pInstancePropertyType.GetGenericArguments()[0];
}
TypeCode typeCode = Type.GetTypeCode(pInstancePropertyType);
switch (typeCode)
{
case TypeCode.Boolean:
pInstance.SetValue(response, Convert.ToBoolean(listValue));
break;
case TypeCode.Byte:
pInstance.SetValue(response, Convert.ToByte(listValue));
break;
case TypeCode.Char:
pInstance.SetValue(response, Convert.ToChar(listValue));
break;
case TypeCode.DateTime:
pInstance.SetValue(response, Convert.ToDateTime(listValue));
break;
case TypeCode.DBNull:
pInstance.SetValue(response, Convert.DBNull);
break;
case TypeCode.Decimal:
pInstance.SetValue(response, Convert.ToDecimal(listValue));
break;
case TypeCode.Double:
pInstance.SetValue(response, Convert.ToDouble(listValue));
break;
case TypeCode.Empty:
pInstance.SetValue(response, "");
break;
case TypeCode.Int16:
pInstance.SetValue(response, Convert.ToInt16(listValue));
break;
case TypeCode.Int32:
pInstance.SetValue(response, Convert.ToInt32(listValue));
break;
case TypeCode.Int64:
pInstance.SetValue(response, Convert.ToInt64(listValue));
break;
case TypeCode.SByte:
pInstance.SetValue(response, Convert.ToSByte(listValue));
break;
case TypeCode.Single:
pInstance.SetValue(response, Convert.ToSingle(listValue));
break;
case TypeCode.String:
pInstance.SetValue(response, Convert.ToString(listValue));
break;
case TypeCode.UInt16:
pInstance.SetValue(response, Convert.ToUInt16(listValue));
break;
case TypeCode.UInt32:
pInstance.SetValue(response, Convert.ToUInt32(listValue));
break;
case TypeCode.UInt64:
pInstance.SetValue(response, Convert.ToUInt64(listValue));
break;
}
}
}
return response;
}
Related
I'm currently learning C# and WPF, and i'm trying to simulate a circuit of logic gates and flipflops, but it won't work.
Could someone please show me a possible way to achive this? (maybe a simple similar application?)
What i have tried so far:
Class:
public class GateBase
{
public Type Type { get; set; }
public GateBase Input1 { get; set; }
public GateBase Input2 { get; set; }
public List<GateBase> Outputs { get; set; }
public bool Evaluated { get; set; }
public bool Value { get; set; }
public bool FlipFlop { get; set; }
public GateBase(Type type = Type.OFF, Gate input1 = null, Gate input2 = null)
{
Type = type;
Input1 = input1;
Input2 = input2;
Outputs = new List<GateBase>();
Evaluated = false;
Value = false;
FlipFlop = false;
switch (Type)
{
case Type.T:
case Type.D:
case Type.SR:
case Type.JK: FlipFlop = true; break;
}
}
public bool Evaluate()
{
if (!Evaluated)
{
bool input1 = false;
bool input2 = false;
if (Input1 != null)
{
if (Input1.FlipFlop)
input1 = Input1.Value;
else
input1 = Input1.Evaluate();
}
if (Input2 != null)
{
if (Input2.FlipFlop)
input2 = Input2.Value;
else
input2 = Input2.Evaluate();
}
switch (Type)
{
case Type.OFF:
Value = false; break;
case Type.ON:
Value = true; break;
case Type.OUT:
Value = input1; break;
case Type.CON:
Value = input1; break;
case Type.NOT:
Value = input1; break;
case Type.AND:
Value = input1 & input2; break;
case Type.OR:
Value = input1 | input2; break;
case Type.XOR:
Value = input1 ^ input2; break;
case Type.NAND:
Value = !(input1 & input2); break;
case Type.NOR:
Value = !(input1 | input2); break;
case Type.XNOR:
Value = !(input1 ^ input2); break;
case Type.D:
Value = input1; break;
case Type.T:
Value = input1 ? Value : !Value; break;
case Type.SR:
Value = (input1 ^ input2) ? Value : Value; break;
case Type.JK:
Value = (input1 ^ input2) ? input1 : (input1 & input2) ? !Value : Value; break;
default: Value = false; break;
}
}
Evaluated = true;
return Value;
}
public void ResetOutputs()
{
Evaluated = false;
foreach (Gate gate in Outputs)
{
if(!gate.FlipFlop)
{
gate.ResetOutputs();
}
}
}
}
Loop:
Update all logic gates
Update all flipflops and unevaluate outputs of each flipflop (if they are not a flipflop)
public List<GateBase> Gates { get; set; }
while (loop)
{
bool evaluating = true;
while (evaluating)
{
evaluating = false;
foreach (Gate gate in Gates)
{
switch (gate.Type)
{
case Model.Type.ON:
case Model.Type.OFF:
gate.Value = gate.Evaluate();
break;
case Model.Type.OUT:
case Model.Type.CON:
case Model.Type.NOT:
if (gate.Input1 != null && (gate.Input1.Evaluated || gate.Input1.FlipFlop))
{
gate.Value = gate.Evaluate();
}
break;
case Model.Type.AND:
case Model.Type.OR:
case Model.Type.XOR:
case Model.Type.NAND:
case Model.Type.NOR:
case Model.Type.XNOR:
if (gate.Input1 != null && gate.Input2 != null)
{
if ((gate.Input1.Evaluated || gate.Input1.FlipFlop) && (gate.Input2.Evaluated || gate.Input2.FlipFlop))
{
gate.Value = gate.Evaluate();
}
}
else
{
evaluating = true;
}
break;
}
}
}
evaluating = true;
while (evaluating)
{
evaluating = false;
foreach (Gate gate in Gates)
{
switch (gate.Type)
{
case Model.Type.D:
case Model.Type.T:
if (gate.Input1 != null && (gate.Input1.Evaluated || gate.Input1.FlipFlop))
{
gate.Value = gate.Evaluate();
gate.ResetOutputs();
}
else
{
evaluating = true;
}
break;
case Model.Type.SR:
case Model.Type.JK:
if (gate.Input1 != null && gate.Input2 != null)
{
if ((gate.Input1.Evaluated || gate.Input1.FlipFlop) && (gate.Input2.Evaluated || gate.Input2.FlipFlop))
{
gate.Value = gate.Evaluate();
gate.ResetOutputs();
}
}
else
{
evaluating = true;
}
break;
}
}
}
}
Problem:
If i'm using the JK-flipflop the results are not as expected. (but the T-flipflop works fine)
Here a link to the solution: Solution on GitHub
Thank You!
You have no break for your switch cases inside the while loop, so if the case is Model.Type.AND it will fall all the way down to the Model.Type.XNOR and I assume this isn't intended. This might be your problem (or at least a part of it).
Just to give you an idea, this small example will output "no break". x = 3 will output the string from default.
using System;
public class Program
{
public static void Main()
{
int x = 1;
switch(x){
case 0:
Console.WriteLine("Break");
break;
case 1:
case 2:
Console.WriteLine("no break");
break;
case 3:
default:
Console.WriteLine("End!");
break;
}
}
}
You can read more about the traditional switch here:
switch C# reference from Micrsoft
Now i fixed a problem and it's working much better than before. (i was resetting the gates before all flipflops were updated)
But it's still not working 100% correct...
Changes in the Loop:
// new list
List<Gate> gatesToResetOutputs = new List<Gate>();
while(loop)
{
while(evaluating gates)
{
...
}
while(evaluating flipflops)
{
...
// instead of
gate.ResetOutputs();
// replace with
gatesToResetOutputs.Add(gate);
...
}
// and at the end of the loop
foreach(Gate gate in gatesToResetOutputs)
{
gate.ResetOutputs();
}
}
I currently have a list builder from a separate class:
public class psuedoMe {
public string relName { get; set; }
public List<string> lstName { get; set; }
}
I have a function that populates this, but then writes it to Json using Newtonsoft.Json.JsonWriter:
private static string returnJson(List<psuedoMe> sentList)
{
StringBuilder jsonSB = new StringBuilder();
StringWriter jsonSW = new StringWriter(jsonSB);
using (JsonWriter jsonWrite = new JsonTextWriter(jsonSW))
{
jsonWrite.WriteStartArray();
foreach (psuedoMe sentItem in sentList)
{
jsonWrite.WriteStartObject();
foreach (System.Reflection.PropertyInfo propInfo in sentItem.GetType().GetProperties())
{
jsonWrite.WritePropertyName(propInfo.Name);
jsonWrite.WriteValue(propInfo.GetValue(sentItem, null));
}
jsonWrite.WriteEndObject();
}
jsonWrite.WriteEndArray();
}
return jsonSB.ToString();
}
However I am receiving an error when it tries to write the public List<string> lstName into jsonSB. I've tried excluding only the lstName from the JsonWriter however this only then loops through the list and doesn't write it to the jsonSB at the end.
Is there anyway of using the above returnJson to write to the list of strings?
There error I get is: Newtonsoft.Json.JsonWriterException: Unsupported type: System.Collections.Generic.List1[System.String].
Which version of JSON.NET you're using? Here's the source code of JsonWriter class's WriteValue method
public virtual void WriteValue(object value)
{
if (value == null)
{
WriteNull();
return;
}
else if (value is IConvertible)
{
IConvertible convertible = value as IConvertible;
switch (convertible.GetTypeCode())
{
case TypeCode.String:
WriteValue(convertible.ToString(CultureInfo.InvariantCulture));
return;
case TypeCode.Char:
WriteValue(convertible.ToChar(CultureInfo.InvariantCulture));
return;
case TypeCode.Boolean:
WriteValue(convertible.ToBoolean(CultureInfo.InvariantCulture));
return;
case TypeCode.SByte:
WriteValue(convertible.ToSByte(CultureInfo.InvariantCulture));
return;
case TypeCode.Int16:
WriteValue(convertible.ToInt16(CultureInfo.InvariantCulture));
return;
case TypeCode.UInt16:
WriteValue(convertible.ToUInt16(CultureInfo.InvariantCulture));
return;
case TypeCode.Int32:
WriteValue(convertible.ToInt32(CultureInfo.InvariantCulture));
return;
case TypeCode.Byte:
WriteValue(convertible.ToByte(CultureInfo.InvariantCulture));
return;
case TypeCode.UInt32:
WriteValue(convertible.ToUInt32(CultureInfo.InvariantCulture));
return;
case TypeCode.Int64:
WriteValue(convertible.ToInt64(CultureInfo.InvariantCulture));
return;
case TypeCode.UInt64:
WriteValue(convertible.ToUInt64(CultureInfo.InvariantCulture));
return;
case TypeCode.Single:
WriteValue(convertible.ToSingle(CultureInfo.InvariantCulture));
return;
case TypeCode.Double:
WriteValue(convertible.ToDouble(CultureInfo.InvariantCulture));
return;
case TypeCode.DateTime:
WriteValue(convertible.ToDateTime(CultureInfo.InvariantCulture));
return;
case TypeCode.Decimal:
WriteValue(convertible.ToDecimal(CultureInfo.InvariantCulture));
return;
case TypeCode.DBNull:
WriteNull();
return;
}
}
#if !PocketPC && !NET20
else if (value is DateTimeOffset)
{
WriteValue((DateTimeOffset)value);
return;
}
#endif
else if (value is byte[])
{
WriteValue((byte[])value);
return;
}
throw new ArgumentException("Unsupported type: {0}. Use the JsonSerializer class to get the object's JSON representation.".FormatWith(CultureInfo.InvariantCulture, value.GetType()));
}
As you can see, it doesn't have support for List<T>. So for List<T> it will throw Unsupported type exception, and even in exception message it is suggesting to use JsonSerializer to get object's JSON representation.
I am making C# code generation with T4 for an ASP.NET Web API project... I need a simple way to convert an EdmType to JsonSchemaType.
Thanks!
Since time flies, I ended up writing a switch, until I find a better solution...
public static class TypeMapper
{
public static JsonSchemaType Convert(EdmType edmType)
{
switch (edmType.BuiltInTypeKind )
{
case BuiltInTypeKind.EnumType:
return JsonSchemaType.String;
case BuiltInTypeKind.ComplexType:
return JsonSchemaType.Object;
case BuiltInTypeKind.PrimitiveType:
return GetPrimitiveType(edmType);
default:
return JsonSchemaType.Null;
}
}
private static JsonSchemaType GetPrimitiveType(EdmType edmType)
{
switch (edmType.Name)
{
case "String":
case "Guid":
case "DateTime":
return JsonSchemaType.String;
case "Int32":
return JsonSchemaType.Integer;
case "Single":
case "Double":
return JsonSchemaType.Float;
default:
return JsonSchemaType.Null;
}
}
}
How will a C# switch statement's default label handle a nullable enum?
Will the default label catch nulls and any unhandled cases?
If it's null, it will hit the default label.
public enum YesNo
{
Yes,
No,
}
public class Program
{
public static void Main(string[] args)
{
YesNo? value = null;
switch (value)
{
case YesNo.Yes:
Console.WriteLine("Yes");
break;
case YesNo.No:
Console.WriteLine("No");
break;
default:
Console.WriteLine("default");
break;
}
}
}
The program will print default.
Unless null is handled.
public class Program
{
public static void Main(string[] args)
{
YesNo? value = null;
switch (value)
{
case YesNo.Yes:
Console.WriteLine("Yes");
break;
case YesNo.No:
Console.WriteLine("No");
break;
case null:
Console.WriteLine("NULL");
break;
default:
Console.WriteLine("default");
break;
}
}
}
prints NULL.
If you have an unhandled enum value that was added later:
public enum YesNo
{
Yes,
No,
FileNotFound,
}
public class Program
{
public static void Main(string[] args)
{
YesNo? value = YesNo.FileNotFound;
switch (value)
{
case YesNo.Yes:
Console.WriteLine("Yes");
break;
case YesNo.No:
Console.WriteLine("No");
break;
default:
Console.WriteLine("default");
break;
}
}
}
It still prints default.
You can use the null-coalescing operator ?? to route null switch values to a specific case label other than default:
public static IEnumerable<String> AsStrings(this IEnumerable<Char[]> src)
{
Char[] rgch;
var e = src.GetEnumerator();
while (e.MoveNext())
{
switch ((rgch = e.Current)?.Length ?? -1)
{
case -1: // <-- value when e.Current is 'null'
yield return null;
break;
case 0:
yield return String.Empty;
break;
case 1:
yield return String.Intern(new String(rgch[0], 1));
break;
default: // 2...n
yield return new String(rgch);
break;
}
}
}
You can have a case for null.
switch (MyNullableEnum)
{
case Option1:
break;
case Option2:
break;
case Option3:
break;
case null:
break;
default:
break;
}
It's worth to mention that C# 8.0 introduced a new Property Pattern for a switch expression. Now you can implement default logic to switch by using underscore:
public double Calculate(int left, int right, Operator op) =>
op switch
{
Operator.PLUS => left + right,
Operator.MINUS => left - right,
Operator.MULTIPLY => left * right,
Operator.DIVIDE => left / right,
_ => 0 // default
}
Ref. https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8
I'm working with a database that is only capable of supporting data types that I have written code for.
I created an Enum parameter with a list of available types.
public enum TableDataType
{
None=0, String=1, Integer=2, Character=3, Boolean=4, DateTime=5, Decimal=6
}
This works, but I still have to process going in and coming back out of my data structures:
TableDataType GetMyType(DataGridViewColumn col) {
TableDataType type;
if (col.ValueType == typeof(bool)) {
type = TableDataType.Boolean;
} else if (col.ValueType == typeof(char)) {
type = TableDataType.Character;
} else if (col.ValueType == typeof(DateTime)) {
type = TableDataType.DateTime;
} else if (col.ValueType == typeof(Decimal)) {
type = TableDataType.Decimal;
} else if (col.ValueType == typeof(Int32)) {
type = TableDataType.Integer;
} else if (col.ValueType == typeof(string)) {
type = TableDataType.String;
} else {
throw new ArgumentException(string.Format("Data Type of '{0}' is not supported.", col.ValueType));
}
return type;
}
Then there is code going the other way...
Type GetSystemType(TableDataType myType) {
Type sysType;
switch (myType) {
case TableDataType.Boolean: sysType = typeof(bool); break;
case TableDataType.Character: sysType = typeof(char); break;
case TableDataType.DateTime: sysType = typeof(DateTime); break;
case TableDataType.Integer: sysType = typeof(Int32); break;
case TableDataType.Decimal: sysType = typeof(Decimal); break;
case TableDataType.String: sysType = typeof(string); break;
default: throw new ArgumentOutOfRangeException(string.Format("Data Type '{0}' is not allowed.", cd.DataType));
}
return sysType;
}
The problem comes from using routines similar to these at more than one spot in my code. If I tell a DataGridViewColumn that it is formatted for an Int32 then pass it an Integer, I get ArgumentException errors.
I'm looking for a good, fast class wrapper that cleverly stores the value and a select range of acceptable data types.
[EDIT] Solution I came up with:
Using the information provided in harpo's comment and Bas's solution, I created this class:
public static class Enumerate {
private Enumerate() {
throw new NotSupportedException();
}
public static SqlDbType ForSqlCe(System.Type item) {
return sqlDbCode(item);
}
public static SqlDbType ForSqlCe(TableDataType item) {
return sqlDbCode(item.GetType());
}
static SqlDbType sqlDbCode(System.Type item) {
switch (Type.GetTypeCode(item)) {
case TypeCode.Boolean: return SqlDbType.Bit;
case TypeCode.Byte:
case TypeCode.Char:
case TypeCode.SByte: return SqlDbType.NChar;
case TypeCode.DateTime: return SqlDbType.DateTime;
case TypeCode.Decimal:
case TypeCode.Double:
case TypeCode.Single: return SqlDbType.Decimal;
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64: return SqlDbType.Int;
case TypeCode.String: return SqlDbType.NVarChar;
case TypeCode.DBNull:
case TypeCode.Empty:
case TypeCode.Object:
default: throw new TypeAccessException(item + " unknown");
}
}
public static TableDataType ForTableData(SqlDbType item) {
return tableDataCode(item.GetType());
}
public static TableDataType ForTableData(System.Type item) {
return tableDataCode(item);
}
static TableDataType tableDataCode(System.Type item) {
switch (Type.GetTypeCode(item)) {
case TypeCode.Boolean: return TableDataType.Boolean;
case TypeCode.Byte:
case TypeCode.Char:
case TypeCode.SByte: return TableDataType.Character;
case TypeCode.DateTime: return TableDataType.DateTime;
case TypeCode.Decimal:
case TypeCode.Double:
case TypeCode.Single: return TableDataType.Decimal;
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64: return TableDataType.Integer;
case TypeCode.String: return TableDataType.String;
case TypeCode.DBNull:
case TypeCode.Empty:
case TypeCode.Object:
default: throw new TypeAccessException(item + " unknown");
}
}
public static Type ForWin32(string item) {
string text = item.Trim().ToLower();
switch (text) {
case "boolean":
case "bool":
case "bit": return typeof(bool);
case "byte":
case "char":
case "sbyte": return typeof(char);
case "date":
case "datetime":
case "time": return typeof(DateTime);
case "decimal":
case "double":
case "numeric":
case "single": return typeof(Double);
case "int":
case "int16":
case "int32":
case "int64":
case "integer":
case "uint16":
case "uint32":
case "uint64": return typeof(Int32);
case "string": return typeof(string);
default:
throw new TypeAccessException(item + " unknown");
}
}
public static Type ForWin32(SqlDbType item) {
return win32Code(item.GetType());
}
public static Type ForWin32(TableDataType item) {
return win32Code(item.GetType());
}
static Type win32Code(System.Type item) {
switch (Type.GetTypeCode(item)) {
case TypeCode.Boolean: return typeof(bool);
case TypeCode.Byte:
case TypeCode.Char:
case TypeCode.SByte: return typeof(char);
case TypeCode.DateTime: return typeof(DateTime);
case TypeCode.Decimal:
case TypeCode.Double:
case TypeCode.Single: return typeof(Decimal);
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64: return typeof(Int32);
case TypeCode.String: return typeof(string);
case TypeCode.DBNull:
case TypeCode.Empty:
case TypeCode.Object:
default: throw new TypeAccessException(item + " unknown");
}
}
}
If you dont want to use System.TypeCode like harpo suggests, use Type.GetType():
string assemblyQualifiedName = "System.{0}, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
string typeString = myEnumValue.ToString();
Type type = Type.GetType(string.Format(assemblyQualifiedName, typeString));
Another option is to store the mapping in a Dictionary:
static class TypeResolver
{
static Dictionary<TableDataType, Type> typeLookup = new Dictionary<TableDataType, Type>();
static TypeResolver()
{
typeLookup.Add(TableDataType.Integer, typeof(Int32));
typeLookup.Add(TableDataType.String, typeof(String));
}
public static Type Resolve(TableDataType tableType)
{
return typeLookup[tableType];
}
}