I have a problem to (de)serialize DynamicObject with other json library that is not Newtownsoft.Json.
(Jil, NetJSON, ServiceStack.Text...)
This is my expandable object class:
public class ExpandableObject : DynamicObject
{
private readonly Dictionary<string, object> _fields = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
[JsonIgnore]
public Dictionary<string, object> Extra { get { return _fields; } }
public override IEnumerable<string> GetDynamicMemberNames()
{
var membersNames = GetType().GetProperties().Where(propInfo => propInfo.CustomAttributes
.All(ca => ca.AttributeType != typeof (JsonIgnoreAttribute)))
.Select(propInfo => propInfo.Name);
return Extra.Keys.Union(membersNames);
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
return _fields.TryGetValue(binder.Name, out result);
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
_fields[binder.Name] = value;
return true;
}
}
The problem with other libraries (like Jil) that the overridden methods don't invoked.
With Newtonsoft.Json it works just great but the performance is bad.
For example - deserialize test of derived class:
public class Person : ExpandableObject
{
public int Id { get; set; }
}
public class Program
{
public static void Main(string[] args)
{
var json = "{ \"Id\": 12 , \"SomeFiled\" : \"hello\" }";
var person = Jil.JSON.Deserialize<Person>(json);
}
}
There is no exception .. It just ignored the "SomeFiled" field (should be in "Extra")
1.There is any solution?
2.And why Newtonsoft.Json able to perform the operation and JIL cannot? (or other fast library...). I understanded that the overridden methods should invoke by the DLR.. how can I make it work?
Thanks.
EDIT:
now I'm using DeserilizeDynamic instead of Deserialize(T). Now it works and my methods invokes by the DLR.
the only problem for now is DeserilizeDynamic return 'dynamic' and doesn't have generic override (T). And because of that Web API cant resolve the type of the object on POST action for example.
mabye in future...
If you look at the Common Pitfalls document in the wiki (https://github.com/kevin-montrose/Jil/wiki/Common-Pitfalls), you'll see the following:
If you have a class FooBase and a class Bar : FooBase and a call like
JSON.Serialize(myBar), Jil will not serialize members inherited
from FooBase by default. Note that in many cases the generic
parameter can be inferred.
To fix this, pass an Options object with ShouldIncludeInherited set to
true.
Related
I'm making a form application with a 'propertygrid control.'
I want all properties to always display with non-bold text --- always treat all properties as a 'default' value. And this 'Test' class has a lot of properties.
I think the best way is to dynamically implement 'ShouldSerializeXXX' methods. Manually implementation is lacking in flexibility and not smart.
I know the way to dynamically implement a function using ’DynamicMethod class' [https://learn.microsoft.com/en-US/dotnet/api/system.reflection.emit.dynamicmethod?view=net-5.0]. But the 'ShouldSerializeXXX' function has an effect just by defining, I have no idea how to implement the function.
Can anybody tell me the way to do this? Sorry for my poor English.
public class Test
{
public int AAA {get;set;}
public string BBB {get;set;}
public bool CCC {get;set;}
...
...
//This class has a lot of property, so I want to dynamically implement the function like this:
private bool ShouldSerializeAAA(){ return false; }
private bool ShouldSerializeBBB(){ return false; }
...
}
Dynamically implementing a method that needs to then be discovered by reflection is not trivial, and would require dynamically creating a sub-type of Test and making sure that all your instances are actually of the sub-type - not an appealing proposition.
There are some more appealing options, though;
generate the extra methods - this could be a few lines of throw-away reflection code (and a unit test that checks that they all exist) that just spits out however-many versions of public bool ShouldSerialize{Name}() => false;
look into the type-descriptor/property-descriptor API; a custom type-description-provider can provide custom property-descriptors, and it is they that get to say whether something needs to be serialized or not; it is just that the default implementation looks for ShouldSerialize{Name}()
Honestly, option 1 seems by far the easiest option here - and it will involve less mess at runtime; you could get option 1 implemented in a few minutes, including the test to make sure you don't miss any new ones
The basic idea is using a custom type descriptor as it's already addressed in Marc's answer. You can see an implementation in my post here. You can make the linked post working for you easily by changing override of ShouldSerializeValue and return false. That's all.
But here I'd like to share another option, a shorter answer, which needs less effort but basically do the same for you. Using a Proxy when passing objects to PropertyGrid:
Assuming you have a common class like this:
public class MyClass
{
public string MyProperty1 { get; set; }
public string MyProperty2 { get; set; }
public string MyProperty3 { get; set; }
}
This is how you use the proxy:
var myOriginalObject = new MyClass();
this.propertyGrid1.SelectedObject = new ObjectProxy(myOriginalObject);
And here is the result after changing properties:
This is the ObjectProxy which is a class derived from CustomTypeDescriptor will do the magic for you. And here's the class:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
public class ObjectProxy : CustomTypeDescriptor
{
public object Original { get; private set; }
public List<string> BrowsableProperties { get; private set; }
public ObjectProxy(object o)
: base(TypeDescriptor.GetProvider(o).GetTypeDescriptor(o)) => Original = o;
public override PropertyDescriptorCollection GetProperties(Attribute[] a)
{
var props = base.GetProperties(a).Cast<PropertyDescriptor>()
.Select(p => new MyPropertyDescriptor(p));
return new PropertyDescriptorCollection(props.ToArray());
}
public override object GetPropertyOwner(PropertyDescriptor pd) => Original;
}
public class MyPropertyDescriptor : PropertyDescriptor
{
PropertyDescriptor o;
public MyPropertyDescriptor(PropertyDescriptor originalProperty)
: base(originalProperty) => o = originalProperty;
public override bool CanResetValue(object c) => o.CanResetValue(c);
public override object GetValue(object c) => o.GetValue(c);
public override void ResetValue(object c) => o.ResetValue(c);
public override void SetValue(object c, object v) => o.SetValue(c, v);
public override bool ShouldSerializeValue(object c) => false;
public override AttributeCollection Attributes => o.Attributes;
public override Type ComponentType => o.ComponentType;
public override bool IsReadOnly => o.IsReadOnly;
public override Type PropertyType => o.PropertyType;
}
I've got a JSON coming in that I'd like to deserialize into a class A; one of the fields is an array of abstract class B (which has a few concrete implementations). Is it possible to deserialize the abstract-class array correctly without building a custom JsonConverter? Ideally, something native to JSON.net and not verbose, e.g. with TypeNameHandling.All... but I haven't got that particular route to work.
I do not have access to the JSON at serialization-time (if I did, TypeNameHandling would work great), but only at deserialization-time.
To be concrete:
public class A // the top-level class to deserialize
{
public B[] arr;
// other members...
}
public abstract class B
{
// ...some fields...
}
public class C : B
{
// a concrete implementation of B
}
public class D : B
{
// another concrete implementation of B
}
And I receive a JSON that may look like:
{
"arr" : [
{
// a C object
},
{
// a D object
}
]
}
I know you can effectively do something like this really cleanly with XML deserialization using the below; I'm pretty much looking for something similar in JSON.
// tells the deserializer to deserialize the object with field name "C" as a
// class C, and field name "D" as a D
[XmlElement("C", Type = typeof(C))]
[XmlElement("D", Type = typeof(D))]
public B[] arr;
Since you are unable to modify the JSON to use TypeNameHandling you need to create a custom converter that examines the properties to determine which type to return. Let's say you had your derived classes looking like this for example:
public class C : B
{
public string CProperty { get; set; }
}
public class D : B
{
public string DProperty { get; set; }
}
You could have a custom converter class that looks like this:
public class BConverter : JsonConverter
{
public override object ReadJson(JsonReader reader, Type type,
object value, JsonSerializer serializer)
{
JObject jobject = JObject.Load(reader);
if (jobject.ContainsKey("CProperty"))
{
return jobject.ToObject<C>(serializer);
}
if (jobject.ContainsKey("DProperty"))
{
return jobject.ToObject<D>(serializer);
}
throw new Exception("Um, this is some other type!");
}
public override bool CanConvert(Type type) => type == typeof(B);
public override bool CanWrite => false;
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
=> throw new NotImplementedException();
}
Now you can deserialise like this:
var result = JsonConvert.DeserializeObject<A>(json, new BConverter());
This is the first time I am writing a simple custom attribute. Let me first show that what I have done
providers.cs
public enum Providers
{
Employee,
Product
};
MyCustomAttribute.cs
[AttributeUsage(AttributeTargets.Class) ]
public class ServiceProvider : System.Attribute
{
private Providers provider;
public ServiceProvider(Providers provider)
{
this.provider = provider;
}
public Providers CustomProvider
{
get
{
return provider;
}
}
}
A.cs
[ServiceProvider(Providers.Employee)]
public class A
{
public void SomeMethod()
{
Console.WriteLine(Dataclass.GetRecord("Employee"));
}
}
B.cs
[ServiceProvider(Providers.Product)]
public class B
{
public void SomeMethod()
{
Console.WriteLine(Dataclass.GetRecord("Product"));
}
}
dataclass.cs
public static class Dataclass
{
public static string GetRecord(string key)
{
return InfoDictionary()[key];
}
private static Dictionary<string, string> InfoDictionary()
{
Dictionary<string, string> dictionary = new Dictionary<string, string>();
dictionary.Add("Employee", "This is from Employees");
dictionary.Add("Product", "This is from proucts");
return dictionary;
}
}
At present, I am hard-coding the "keys" from the individual Classes viz. A and B.
What I am looking for is that, if I decorate my Class A with [ServiceProvider(Providers.Employee)] then the GetRecord method should get me the Employee Related Value.
For Class B, if I decorate with [ServiceProvider(Providers.Product)], I should be able to get Product related value.
N.B.~ I know that it is just a simple thing to achieve by passing a Enum also and converting to string, but as I said I am learning the Custom Attribute, so I want to do it in that way only.
Please let me know if it is possible or not and if "Yes" then how can I achieve this?
You access custom attributes through reflection
var type = typeof(A);
var attributes = type.GetCustomAttributes(typeof(ServiceProvider),inherit:false);
That would give you an array of all service provider attributes for class A.
Your example doesn't really show how you want to apply it but to fit with what you have you could have an extension method
public static class ClassExtenstions
{
public static Providers? GetServiceProvider<T>(this T cls) where T : class
{
var attribute = typeof(T).GetCustomAttributes(typeof (ServiceProvider), inherit: false).FirstOrDefault() as ServiceProvider;
return attribute != null ? attribute.CustomProvider : (Providers?)null;
}
}
And in your class you would use it as
[ServiceProvider(Providers.Employee)]
public class A
{
public void SomeMethod()
{
var provider = this.GetServiceProvider();
Console.WriteLine(Dataclass.GetRecord(provider.ToString()));
}
}
I have a file that looks like the following:
public abstract class TestStep
{
public abstract bool DoWork();
public abstract List<TestStep> PrerequisiteSteps { get; set; }
public abstract string DisplayForm { get; }
}
class TestFunctions
{
public class A : TestStep
{
public override string DisplayForm { get { return "MainForm; } }
// remaining implementation goes here...
}
public class B : TestStep { // some implementation }
public class C : TestStep { // some implementation }
public static void NextStep() { }
}
I'd like to serialize the classes A, B, and C to an XML file. I can manually add instances of these classes to a List<TestStep> object and pass that to an XML serializer, but I'd like to programmatically accomplish this because I might add or remove classes in TestFunctions in the future. As a result, I've found that I can use reflection to get an array of the functions:
Type type = (typeof(TestEngineFunctions));
Type[] testEngineFunctions = type.GetNestedTypes(BindingFlags.Public);
However I'm not sure how to proceed from here. I have access to the name of the functions, I can get their properties as well, but ultimately I don't have an actual object to serialize.
Am I on the right track or is there another method better suited for this?
You can get a new instance of the objects like this:
ObjectType instance = (ObjectType)Activator.CreateInstance(objectType);
Since you may not know the ObjectType before run time you could use the dynamic type and don't cast:
dynamic instance = Activator.CreateInstance(objectType);
However, if you attempt to serialize right after you instantiate you'll just get the default values of the object in your XML.
I have custom data type classes which I want .NET to convert to JSON (and later also back to CustomDataType).
I know that classes without any special definition will be converted to objects, simply by serializing all public properties. But this is not what I need.
Let's assume that I have a class
public class MyString : System.Object {
private string myString;
public MyString(string str) {
this.myString = str;
}
public override bool Equals(System.Object obj)
public override int GetHashCode()
public string ToString() {
return "!!!"+myString+"!!!";
}
}
Now, if I use this type in my ApiController
public class MyItem {
public MyString someStr;
}
public class MyApiController : ApiController {
[HttpGet]
public MyItem MyApi() {
MyItem item = new MyItem();
item.someStr = new MyString("I have a dream");
return item;
}
}
I get
{"someStr":{}}
but I may want to get
{"someStr":"!!!I have a dream!!!"}
or
{"someStr":{"words":4,"chars":11,"length":14}}
without actually exposing any properties as public.
How would I achieve that?
WebApi is using a Json serializer to get your result, when you're expecting it to execute a ToString() on it.
I personally haven't dealt with a lot of private variables (or properties) when serializing objects, however, it doesn't surprise me that it's doing this.
In order to get the desired result, you'll need to expose a property that returns !!!<whatever text>!!!.