I have a class Response with generic parameter:
public class Response<T> where T : class {
public bool Result;
public T Data;
}
Also, I have a class Instance with simple parameters
public sealed class Instance {
public long Rank { get; set; }
public int ID_Member { get; set; }
}
And then I have a class where I use last ones
public sealed class InstanceResponse : Response<IList<Instance>> { }
And I try to add a constructor to last class and don't understand how to do it
I've tried like there, but it's doesn't work, JsonString contains serialized class InstanceResponse
public sealed class InstanceResponse : Response<IList<Instance>> {
public InstanceResponse(string JsonString) {
this = JsonConvert.DeserializeObject<InstanceResponse>(JsonString);
}
}
I've got an error Cannot assign to 'this' because it is read-only
How it possible?
It's not possible to deserialize json to the object and assign it directly in ctor to the object itself using this keyword.
Provided that
Json contains serialized class InstanceResponse
You can do something like this:
public sealed class InstanceResponse : Response<IList<Instance>> {
public InstanceResponse(string JsonString) {
var response = JsonConvert.DeserializeObject<InstanceResponse>(JsonString);
this.Data = response.Data;
this.Result = response.Result;
}
}
Another possible solution is to deserialize json in a code that creates instance of InstanceResponse (call's ctor) somewhere.
Instead of:
var response = new InstanceResponse(json);
You could deserialize json right there:
var response = JsonConvert.DeserializeObject<InstanceResponse>(json);
P.S.
With that being said, an interesting point was raised by #Lasse Vågsæther Karlsen regarding the subject. It is actually possible to assign something to this however it is only working inside of a structs ctor and use cases for it are very limited...(thanks Lasse)
Related
I am working on writing a client library for reading from an MQTT API (that I have no control over).
For making requests I have a helper Request class that has all the default request parameters that always need to be provided. Each request has a payload property. I implemented this by making the Request class a generic class like: public class Request<T> where T : IRequestPayload and that has worked great, with one exception, when the request payload is only a string. Since string doesn't implement IRequestPayload, I cant make a Request with a payload of type string.
While looking into ways to handle this I wondered if it would be possible to flatten a derived Request class's Value property and save it to Payload. An example of what I mean is below:
Classes:
public interface IPayload { }
public interface IRequestPayload : IPayload { }
public abstract class Request<T> where T : IRequestPayload {
public T? Payload { get; set; } = null;
}
public class MyAPIRequestPayload : IRequestPayload {
public string Value { get; set; }
}
public class MyAPIRequest : Request<MyAPIRequestPayload> {
}
Desired JSON Input/Output:
{
"Payload":"MyValue"
}
Desired object values:
MyAPIRequest.Payload = instanceof(MyAPIRequestPayload)
MyAPIRequestPayload.Value = "MyValue"
Edit:
Added in the payload marker interfaces.
I have a project with about 200 classes which need to be saved as json and deserialized back later.
All the classes are immutable and due to this fact I need to inject all complex types into the constructor, otherwise deserialization does not work. Because I use a Clonable base class I don't initialize every parameter in the constructor. When I forget to add a single class to the construtor or misspell it, deserialization does not work anymore and the only way I know to check is to write a lot of unit tests with sample data.
This is a sample to reproduce my problem:
static void Main(string[] args)
{
var immutableClass = new ImmutableClass(new OtherImmutableClass(2)).WithAnyProperty(1);
var jsonString = JsonConvert.SerializeObject(immutableClass, Formatting.Indented);
var deserializedObject = JsonConvert.DeserializeObject<ImmutableClass>(jsonString);
}
public class ImmutableClass : Clonable<ImmutableClass>
{
public ImmutableClass(OtherImmutableClass otherImmutableClassInstance)
{
OtherImmutableClassInstance = otherImmutableClassInstance;
}
public OtherImmutableClass OtherImmutableClassInstance { get; }
[JsonProperty]
public int AnyProperty { get; private set; }
public ImmutableClass WithAnyProperty(int newValue)
{
return With(s => s.AnyProperty = newValue);
}
}
public class OtherImmutableClass
{
public OtherImmutableClass(int completelyWrongPropertyName)
{
MyProperty = completelyWrongPropertyName;
}
public int MyProperty { get; }
}
public abstract class Clonable<T> where T : Clonable<T>
{
protected T With(Action<T> updateAction)
{
var clone = (T)MemberwiseClone();
updateAction(clone);
return clone;
}
}
After serialization the content of my jsonString is as expected:
{
"OtherImmutableClassInstance": {
"MyProperty": 2
},
"AnyProperty": 1
}
When I deserialize no Exception is thrown but the MyProperty is 0 instead of 2 because of completelyWrongPropertyName does not match MyProperty in the constructor of OtherImmutableClass.
Is there an easy way to check if my model is serializable and deserializable without writing UnitTests for each class?
I am searching something like JsonChecker<ImmutableClass>.CanSerializeAndDeserialize();
I already asked google but found no solution.
Bofore I would like to ask my question, please read the follwing classes:
public class JsonPackage<A> : USOPackage
{
public JsonPackage(PackageHeader header, object o) : base(header, StringCompressor.CompressString(JsonConvert.SerializeObject(o, Formatting.Indented))) { }
public new A Content
{
get
{
return JsonConvert.DeserializeObject<A>(this.getContentAsString());
}
}
new public string getContentAsString()
{
return StringCompressor.DecompressString(base.getContentAsString());
}
}
(this class includes USOPackage(!))
and a second class:
public class LoginResponsePackage : JsonPackage<LoginResponse>
{
public LoginResponsePackage(LoginResult result) : base(PackageHeader.USO_AUTH_LOGIN_RESPONSE, new LoginResponse(result)) { }
public class LoginResponse
{
public LoginResult Result;
public LoginResponse(LoginResult r)
{
this.Result = r;
}
}
public enum LoginResult
{
OK,
FailedPassword,
FailedUsername,
FailedProtocolVersion
}
}
Now I would like to convert a "USOPackage" to an "LoginResponsePackage" to get the "Content" of the package in the right type.
If i do it like that:
JsonPackage<LoginResponsePackage.LoginResponse> responsePackage = (JsonPackage<LoginResponsePackage.LoginResponse>)usopackage;
So if I try to get "Content" it works which means i get a LoginResponse by calling
responsePackage.Content
but when i convert the class like that
LoginResponsePackage responsePackage = (LoginResponsePackage)usopackage;
I am not able to access the LoginReponse. It just give me access to for instance: BeginInvoke(), Method, Target, Clone()
I don't know where this comes from..
So my question is what do i have to change in my code to be ablt to directly cast the package so i get a "LoginResponse" by accessing "LoginResponsePackage.Content"
The problem is in this line of code:
public class LoginResponsePackage : JsonPackage<LoginResponse>
The type LoginResponse in this context doesn't mean the nested class you've defined in LoginResponsePackage, it refers to some type outside the class, I guess a delegate from your description of the methods there. You are not inside the class scope yet, so you have to refer to the nested type via its name you would use outside the class: LoginResponsePackage.LoginResponse.
The fixed line:
public class LoginResponsePackage : JsonPackage<LoginResponsePackage.LoginResponse>
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.
Suppose I have a class in SilverLight:
public class GenericClass {
public string filedOne = "field one";
public string filedTwo = "field two";
}
And I want to pass an instance of it to JavaScript to access in the following way:
function callback(obj) {
console.log(obj.fieldOne);
}
Is this possible without serializing to JSON and back?
UPDATE:
I know how to pass primitive values - that's not a problem. I need to pass an object with several fields.
public partial class TestPage: UserControl
{
public TestPage()
{
InitializeComponent();
MyClass myObject = new MyClass();
myObject.SomeMember = "TEST";
HtmlPage.Window.Invoke("JSFunction", myObject);
}
}
UPDATE:
In order to pass non-primitive type objects to javascript; the class definition shall be marked with ScriptableType attribute. All properties of this class shall also be marked with ScriptableMember attribute.
[ScriptableType]
public class MyClass
{
[ScriptableMember]
public string SomeMember { get; set; }
}
Use the ScriptableTypeAttribute
[ScriptableType]
public class SMT_ScriptableManagedType
{
[ScriptableMember(EnableCreateableTypes = false)] // No access
public string GetString1()
{ return "abcdefg"; }
public string GetString2() // Can be accessed.
{ return "123456"; }
}
Now you can pass the object like this:
HtmlPage.Window.Invoke("ReceiveSMT", new SMT_ScriptableManagedType());
Where ReceiveSMT is a javascript function which will receive the object as a parameter.