fromI have this linq query to build a json (of string and bool?) from an IQueryable :
var ret = from c in results select new { country = c.EN, schengen = c.Schengen };
I would like to append new items to it manually : (pseudo code)
ret = ret /* add this -> */ { country = "some new country", schengen = true }
I've tried to do that :
//End up with cannot convert from AnonymousType#2 to AnonymousType#1
var listRet = ret.ToList();
listRet.Add(new { country ="", schengen = true });
As it is an anonymous type that I build I cannot find a way to add it. I always end up with conversion error
Anonymous types are still statically typed and C# compiler generates a separate class for each anonymous type definition occurrence. You need a named class in this case. It's a good practice for data transfer objects anyway. I use JSON DTOs like this, using data annotations and DataContractJsonSerializer.
[DataContract]
public class CountryInfo
{
[DataMember(Name = "country")]
public string Country { get; set; }
[DataMember(Name = "schengen", EmitDefaultValue = false)
public bool? Schengen { get; set; }
}
This way I have a well-documented JSON "protocol", which also uses C# naming conventions before serialization, but JS naming conventions after.
Well it's obvious. Generics are invariant. So another type won't fit. You can use List<object> or a named class to store the values.
If you want to change the result manually, you need to cast it into a static type instead of a dynamic one. Create a class that has a string country and bool schengen(You can even create the class within your current class to hide it from the rest of the application, if that's applicable), cast your linq results into that and then just add to it.
Related
I need to customize the way Newtonsoft.Json serializes an object, in particular about Enum types.
Given a sample class like this:
public class TestEnumClass
{
public Enum ReferencedEnum { get; set; }
public string OtherProperty { get; set; }
public StringSplitOptions OtherEnum { get; set; }
}
The default serialization will happen this way:
var testEnumClass = new TestEnumClass
{
ReferencedEnum = StringComparison.OrdinalIgnoreCase,
OtherProperty = "Something",
OtherEnum = StringSplitOptions.None
};
var serialized = JsonConvert.SerializeObject(testEnumClass, Formatting.Indented);
And the serialized string will be:
{
"ReferencedEnum": 5,
"OtherProperty": "Something",
"OtherEnum": 0
}
Here I have 2 problems:
I cannot guarantee that the order of the Enums will remain the same (here I am using Enums included in the framework, but my project has other Enums that derive from ": Enum"), so I cannot keep the number as the serialized value of the Enum.
Secondly, and more important, is the fact that the "ReferencedEnum" field is declared as "Enum", and any kind of Enum can be written in that field (ReferencedEnum = AnyEnum.AnyEnumValue).
This leads to the fact that when deserializing the value, I need to know the original Enum type (in the example is StringComparison).
I was thinking of using a Converter (deriving from ": JsonConverter") and manipulating what is written and read. The result I was thinking was something like this:
{
"ReferencedEnum": {
"EnumType": "StringComparison",
"EnumValue": "OrdinalIgnoreCase"
},
"OtherProperty": "Something",
"OtherEnum": "StringSplitOptions.None"
}
I this way the deserializer would know:
for "Enum" properties, the original type and the string value.
for "typed Enum" (specific enum) properties, the full type and value.
What I cannot absolutely add is a reference to the converter in the model class like this:
[JsonConverter(typeof(EnumConverter))]
public Enum ReferencedEnum { get; set; }
And I also would avoid to have the "$type" field in the serialized string (except if this is the only solution).
By the way, I can add a generic attribute like this:
[IsEnum]
public Enum ReferencedEnum { get; set; }
Does somebody have any idea of how can I get the result needed?
Thank you!
I've been in the very same issue and developed a nuget package named StringTypeEnumConverter, that solves it.
You can check the project here.
The usage will be as simple as any other converter.
This converter derives from an already existing "StringEnumConverter", that writes the string value of the enum, instead of its numeric counterpart.
I added the support to writing the type name too.
The result will be like: "StringSplitOptions.None" (this is a string value, not an object).
Note that this converter should be applied for both writing and reading, as the resulting json would not be compatible with other readers not including this converter.
You should consider using this package only if you cannot avoid using enums in your model.
I would also suggest you to spend time to check if (custom) enums could be transformed to classes.
J.
I'm getting some JSON as a string and storing it as such:
private static List<object> history = new List<object>();
var data = JsonConvert.DeserializeObject(parsedData);
history.Add(data);
The JSON data looks something like this:
{ id: 12, data: 'my data' }
I'd like to add another method that iterates through the history list, finds an item by its ID and updates it.
What's the best way to access properties on objects like this?
If the incoming JSON string always has the same fields, you can serialize it to a defined class/type.
public class JsonHistory
{
public int id { get; set; }
public string data { get; set; }
}
List<JsonHistory> history = new List<JsonHistory>();
var histData= JsonConvert.DeserializeObject<JsonHistory>(parsedData);
history.Add(histData);
You can also then use linq to find any matches you are looking for:
var matches = history.Where(x => x.id == 10).Select(x => x.data);
You can use dynamic instead of object, because it is easier to use properties rather than object
List<dynamic> history = new List<dynamic>();
string parsedData = "{ id: 12, data: 'my data' }";
var data = JsonConvert.DeserializeObject<dynamic>(parsedData);
history.Add(data);
history.Add(data);
foreach (var o in history)
{
o.id = 13;
}
Also, I strongly suggest you to create a class and use it as known type. That will give you intellisense and definitely you will need that further.
The JSON.NET documentation has the following approach, that I would also suggest using:
First - deserialise to a sensible type (anonymous is fine)
var json = "{id: 12, data: 'my data'}";
var definition = new { Id = 0, Data = "" }
var deserialised = JsonConvert.DeserializeAnonymousType(json, definition);
Second - you've got your first item, so you can "trick" the compiler into letting you use the anonymous type in a list:
var history = (new[] { deserialised }).ToList();
You can then shove any other deserialised instances into that list.
Now you can do your filtering:
var itemImLookingFor = history.SingleOrDefault(x => x.Id == 10);
Once you've then got the item, you can just update it:
itemImLookingFor.Data = itemImLookingFor.Data.ToUpperCase()
I'd recommend reading this as it explains some of the shortcomings inherent in using the dynamic keyword; it's not a bad thing to do, it just has its place.
For this scenario, JSON.NET gives you all the tools you need to either deserialise to a type of your own defining (e.g. write a class that mirrors the JSON, or to an anonymous type like I've done here).
The usual approach is to either deserialize to a custom class or to deserialize to JObject which would allow you to iterate over its properties like using reflection. Both require a lot of typing.
But you can use a clever little trick and get all the benefits of a strong type without having to write the class.
Use an anonymous duck type
Add this method to your library somewhere:
static public T JsonDeserialize<T>(string input, T template)
{
return JsonConvert.DeserializeObject<T>(input);
}
Once you have this in place, you can use it to duck-type the JSON (i.e. get the compiler to infer an anonymous type) by supplying an example instance. This allows you to use anonymous types instead of typing up a custom class.
So for example, to get the row with ID 12, you do something like this:
using System;
using System.Linq;
using Newtonsoft.Json;
public class Program
{
static public T JsonDeserialize<T>(string input, T example)
{
return JsonConvert.DeserializeObject<T>(input);
}
public static void Main()
{
//Sample data with two records
const string input = #"[ { 'id' : 12, 'data' : 'MyData' }, { 'id' : 13, 'data' : 'Another record' } ]";
//Create an example instance so the compiler can use its anonymous type
var example = new []
{
new { id = default(int), data = default(string) }
};
//Pass the example as argument 2 so that the compiler can infer T. The argument itself isn't used for anything.
var list = JsonDeserialize(input, example);
//Now we have a strongly-typed list, without having to write a class
//We can use LINQ or anything else that needs a strong type
foreach ( var o in list.Where( a => a.id == 12) )
{
Console.WriteLine(o.id);
Console.WriteLine(o.data); //Intellisense works here
}
}
}
Output:
12
MyData
Working example on DotNetFiddle.
I have a generic class defined like this:
public abstract class StationProperty{}
public class StationProperty<T>
{
public int Id { get; set; }
public T Value { get; set; }
}
I then have a list that looks like this:
var props = new List<StationProperty>();
So far so good, except when I try to add an item to the list like this:
var prop = new StationProperty<bool>(39, true);
// var prop = new StationProperty<int>(39, 100); another example
props.Add(prop);
It throws a design time error of: Argument type < bool> is not assignable to parameter type X
My idea is to have a list of values which are strongly typed (not using object), then be able to infer their types using generics later down the road.
That's because a StationProperty<T> isn't a StationProperty. The only thing they have in common is a name. Perhaps one should derive from the other?
public class StationProperty<T>:StationProperty{}
StationProperty and StationProperty<T> are two independent classes.
You're creating List of first and inserting there instance of second - that can't be done.
I have two lists of different objects, one from a third party API and one from my database - and I'm trying to link the two as a relationship. Ideally with a similar effect of how DBML's create relationships for tables with foreign keys (Customer.Orders).
From third party:
class ApiObject {
public string ID { get; set; }
public string Title { get; set; }
public DateTime CreatedDate { get; set; }
... 30 other properties ...
}
From my database:
class DbmlObject {
public int ID { get; set; }
public string ApiID { get; set; }
public string OtherString { get; set; }
}
They are related through ApiObject.ID == DbmlObject.ApiID
I do not want to merge these, nor join them into some anonymous object (and explicitly list 30+ properties) - but rather to make the DbmlObject a linked property of ApiObject. i.e.: addressable as:
apiObject.DbmlObjects.First().OtherString or ideally apiObject.DbmlObject.OtherString since it is a 1 to 1 relationship.
In controller:
List<ApiObject> apiObjects = _thirdParty.GetObjects();
DbmlDataContext model = new DbmlDataContext();
List<DbmlObject> dbmlObjects = model.GetAllDbmlObjects();
// relate them here
foreach (var apiObject in apiObjects)
Console.Write(apiObject.DbmlObject.OtherString)
// NOTE: ideally this foreach loop should not make a DBML query on each iteration, just the single GetAllDbmlObjects query above.
It sounds like a join:
var combined = from api in apiObjects
join dbml in dbmlObjects on api.ID equals dbml.ApiID
select new { api, dbml }
In order to get DbmlObject "in" the ApiObject, you will need to either inherit ApiObject and construct a new one of that class, which includes the Dbml property, or create a entirely new class to return. If you need static typing this is the best you can do - of course you could (mis)use dynamic to get what you want.
In this case, you are mentioning (in comments) that the ApiObject class is from a third party library that you can't change - in this case I would probably choose to create a new type which takes an instance of both objects in the constructor and exposes the properties you need - a decorator. Yes, it looks like a lot of code, but it is not complex, good tools will autogenerate it for you - and you get the class that you need for your code to be succinct.
In case you want to go further with returning an IEnumerable<dynamic>, you could build a "combining dynamic" object based on DynamicObject that then responds to all the properties of ApiObject and DbmlObject - or just adds DbmlObject as a property. I am not saying this is the right way to go, it depends on what you need it for - remember you are losing type safety. Here is a simple example:
void Main()
{
dynamic dyn = new CombiningDynamic(new Foo { X = 3 }, new Bar { Y = 42 });
Console.WriteLine(dyn.X);
Console.WriteLine(dyn.Y);
}
public class Foo
{
public int X {get;set;}
}
public class Bar
{
public int Y { get;set;}
}
public class CombiningDynamic : DynamicObject
{
private object [] innerObjects;
public CombiningDynamic(params object [] innerObjects)
{
this.innerObjects = innerObjects;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
foreach(var instance in innerObjects)
{
Type t = instance.GetType();
PropertyInfo prop = t.GetProperty(binder.Name);
if (prop != null && prop.CanRead)
{
result = prop.GetValue(instance, null);
return true;
}
}
result = null;
return false;
}
}
Remember, this is example code. If you really go this way, you would want to perhaps override some more of the methods (TrySetMember, ...), and you most definetely would want to cache the reflection results so you don't need to walk the types each time - reflection is (comparatively) slow.
I have a collection IEnumerable. In a LINQ query, preferably, I would like to select only the properties in this collection from type T, into an anonymous type, where T is a POCO business object.
Example:
My IEnumerable contains properties "Name", "Age".
My POCO is:
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public string Address { get; set; }
public string Phone { get; set; }
}
I want to achieve the same effect as below, but without hard-coding the members of the anonymous type, and instead using my PropertyInfo collection.
IEnumerable<Person> peeps = GetPeople();
var names = from p in peeps
select new {Name = p.Name, Age = p.Age};
If I was using Entity Framework, I could use Entity SQL with a dynamically constructed string where clause, but then although not strictly hard-code, I'm still using string names of the properties.
Could I not perhaps dynamically construct an expression for the .Select projection method that determines which properties are included in the result object?
You can't do that. The compiler needs to know statically the type of the items in the enumeration, even if it's an anonymous type (the var keyword denotes implicit typing, not dynamic typing)
Why do you need to do that ? If you explain what your requirement is, we can probably suggest another way to do it