I have an object graph containing nodes of various types. All nodes derive from a Node class. Using YamlDotNet I've managed to serialize and deserialize the graph by providing my own implementation of IObjectFactory. The only thing left to do is to get rid of a constructor that only exists to please the YamlDotNet serializer.
Have a look at the following .NET fiddle
https://dotnetfiddle.net/KJMzxD
The FancyNode.ctor() is the constructor I would like to remove but I'm not sure how to tell the serializer that I've handled everything in the deserializer. If I simply remove it I get the following error
Type 'FancyNode' cannot be deserialized because it does not have a default constructor or a type converter.
If you only want to get rid of the parameterless constructor code rather than the constructor itself - given it's required for that type of deserialisation - you could remove both constructors and use a factory method to create the nodes. That would result in the class having a default public constructor.
For example, change:
public class FancyNode : Node
{
private IController controller;
public string ID
{
get;
private set;
}
// I would really like to get rid of this constructor
public FancyNode()
{
throw new NotSupportedException();
}
// NOTICE: no default constructor here
public FancyNode(IController controller, string id)
{
this.controller = controller;
this.ID = id;
}
}
to:
public class FancyNode : Node
{
private IController controller;
public string ID
{
get;
private set;
}
public static FancyNode CreateNode(IController controller, string id)
{
var node = new FancyNode();
node.controller = controller;
node.ID = id;
return node;
}
}
Yes you lose the tight control you have that doesn't allow the object to be created without passing those parameters in, given that anyone can now do var x = new FancyNode(). Then again you aren't validating the parameters so it makes no difference to calling it with new FancyNode(null, null).
Related
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 class inherited from an abstarct class. On razor, when I create instance of child class, I got this error as is shown in image:
Cannot create an abstract class
But StuffRegisterSearchParameterVM is not an abstract class. Why this happen?
Controller
public ActionResult SearchRegistration(SearchParameterVM model)
Model
abstract public class SearchParameterVM
{
public string FromDate { get; set; }
public string ToDate { get; set; }
public int? MainTestRegisterId { get; set; }
public int TestTypeId { get; set; }
public bool IsForAnsweringPage { get; set; }
}
public class StuffRegisterSearchParameterVM : SearchParameterVM
{
public int? StuffId { get; set; }
public string Code { get; set; }
}
You can not use abstract class as a parameter of action, because asp.net mvc does not know anything abount posted object type, it trys to create an argument type, and this type is abstract.
So, replace it this concrete class or create special binder.
When you define the action:
public ActionResult SearchRegistration(SearchParameterVM model)
That defines a method that MVC will call based on your routes when an http request is made to the server. That http request probably contains only parameters like you would have if you had a web form. MVC model binding simply creates an instance of the class specified in the parameter to the action in C# and tries to set the property values based on the http parameters passed in the http call. This call could be from a view action like you have, from a static html page, from a program, or anywhere else you can make an http call. When it is an abstract class, it cannot create an instance of it.If you had 3 child classes based on your abstract class, MVC would have no way to tell which type to create.
You can check out this question for some more information.
So how would you determine what concrete class should exist in memory when a call to that action is made, given only parameter names with different values? You could create different routes and actions that had different types in their parameters. You could also check those parameters and create different concrete classes based on the passed parameters. For instance if you wanted to use a certain class based on if the 'code' value is passed, , you'll either have to create your own IModelBinder which could determine which concrete class based on the passed query parameters:
public class MyModelBinder : IModelBinder {
public object BindModel(ControllerContext controllerContext,
ModelBindingContext bindingContext) {
// create different concrete instance based on parameters
ValueProviderResult code = bindingContext.ValueProvider.GetValue("Code");
if (code.AttemptedValue != null) {
// code is passed as a parameter, might be our class
// create instance of StuffRegisterSearchParameterVM and return it
}
// no Code parameter passed, check for others
}
}
Then you have to tell in your startup that you have a special model binder
for your abstract class:
ModelBinders.Binders.Add(typeof(SearchParameterVM), new MyModelBinder());
Or you could do something in your action to determine what type to create and use TryUpdateModel to set the values:
public ActionResult SearchRegistration() {
SearchParameterVM model = null;
if (Request.Parameters["code"] != null) {
model = new StuffRegisterSearchParameterVM();
TryUpdateModel(model); // check return value
}
}
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>!!!.
I'm trying to create attribute which will generate identity number key for each object in class range. So i need to know which class contain parameter connected with attribute.
I create something like this:
class SampleModel
{
[Identity(typeof(SampleModel))]
public int Id { get; set; }
}
public class IdentityAttribute : Attribute
{
private readonly int _step;
private readonly Type _objectType;
public IdentityAttribute(Type type)
{
_step = 1;
_objectType = type;
}
public object GenerateValue()
{
return IdentityGenerator.GetGenerator(_objectType).GetNextNum(_step);
}
}
But i'm wondering is there any method which will allow me to get Type of base class (in this case SampleMethod) in IdentityAttribute constructor without sending it as parameter?
There is no such method -- an instance of Attribute does not know what it was decorating.
But the code that creates the instance does, so depending on usage you could inject this information externally:
var identityAttribute = (IdentityAttribute)Attribute.GetCustomAttribute(...);
// If you can call GetCustomAttribute successfully then you can also easily
// find which class defines the decorated property
var baseClass = ... ;
// And pass this information to GenerateValue
var value = identityAttribute.GenerateValue(baseClass);