I have my ResponseDto which includes a simple string property named Answer.
public string Answer { get; set; }
Now, the requirement came such that I could either be getting an answer as a string, or as an array of int.
I decided to create two classes for this:
public class AnswerType {
public string Answer { get; set; }
}
public class OptionAnswerType {
public int[] AnswerOptionIds { get; set; }
}
I could serialize / deserialize it accordingly.
But to still keep a single response property type, I thought about creating an empty base class:
public class BaseAnswerType { }
public class AnswerType : BaseAnswerType {
public string Answer { get; set; }
}
public class OptionAnswerType : BaseAnswerType {
public Guid[] AnswerOptionIds { get; set; }
}
and change my property in ResponseDto to:
public BaseAnswerType Answer { get; set }
through which via run time, I would be returning either of the two classes.
Is this a bad approach? Any alternate would be greatly appreciated.
Related
There's a lot of Qs on this, but I need a solution without JSON.Net, etc. - I must use the canned stuff in Asp.Net MVC.
How can I serialize a POCO with a dynamic property - and get all the static properties, too? What I found was the dynamic only, or the static type which is easy.
e.g.
public class ReturnThisClassAsJSON {
public int Id {get; set; }
public string Name { get; set; }
public ContainedClass ContainedContents { get; set; }
}
public class ContainedClass {
public int Order { get; set; }
public string Label { get; set; }
public dynamic DynamicInfo { get; set; }
public List<dynamic> DynamicList { get; set }
}
My own answer:
I replaced the dynamic from the DynamicInfo and DynamicList from the ContainedClass with static types.
With the dynamic, I had 1 of 2 choices. Either serialize the dynamic to a string in its own serialization call using above SO question 5156664. (Which left me with the rest of the class I also wanted serialized and merged with it, thus this question). Or, incur this error:
"A circular reference was detected while serializing an object of type 'System.Reflection .RuntimeModule' ".
when attempting a single serialization call on the ContainedClass.
So, I transferred the dynamics into static-typed classes:
public class ColumnValue
{
public string Name { get; set; }
public string Value { get; set; }
}
public class DynamicRow
{
public List<ColumnValue> ColumnValue { get; set; }
}
and, change ContainedClass to this:
public class ContainedClass
{
public List<ColumnValue> DynamicInfo { get; set; }
public List<DynamicRow> Data { get; set; }
}
And, it serializes using out-of-the-box Asp.Net MVC:
return Json(ReturnThisClassAsJSON, JsonRequestBehaviour.AllowGet);
I'm reading user input from different types of CSV files having a few common and a few different attributes. I have created a base class TestCaseData and derived classes as below:
public abstract class TestCaseData
{
public abstract string ID { get; set; }
public abstract string Name{ get; set; }
}
public class DerivedClassOne :TestCaseData
{
public override string ID { get; set; }
public override string Name{ get; set; }
pubic string DerivedOneProperty{ get; set; }
}
public class DerivedClassTwo :TestCaseData
{
public override string ID { get; set; }
public override string Name{ get; set; }
pubic string DerivedTwoProperty{ get; set; }
}
I am reading the CSV file and creating a list of derived classes and assigning to list of base class as below
List<TestCaseData> lstTestCaseData = MethodCallToReturnListOf_DerivedOneClassFromCSV();
As now I have lstTestCaseData I have to validate the user inputs also where I am unable to find a way to write a single method to validate user input of type DerivedOneProperty or DerivedTwoProperty as they have their own properties. Anyone can help me here?
I have method signature something like that
public string ValidateCompleteFile(List<TestCaseData> TestCaseInputList, out bool IsInputValid)
You could instead put an abstract validation method on the TestCaseData class and then let each class that inherits this class implement it how they need to.
public abstract class TestCaseData
{
public abstract string ID { get; set; }
public abstract string Name{ get; set; }
public abstract bool Validate();
}
And then call this method for each entry in the TestCaseInputList collection.
The answer regarding an abstract method is the best solution if you're committed to the code pattern you originally conceived of (i.e. calling a validation method on each object). But perhaps it would be better to validate each field in its setter:
public abstract class TestCaseData
{
private string id, name;
public abstract string ID { get; set; }
public abstract string Name{ get; set; }
}
public class DerivedClassOne : TestCaseData
{
public override string ID
{
get { return id; }
set
{
if ( ... ) throw new ArgumentException();
...
id = value;
}
}
...
}
This way an exception is thrown as soon as an invalid value is encountered. Imagine if you created a million of these objects before checking if each one was valid, only to find that the very first one was invalid. This solution avoids a situation like that by proactively validating as the properties are set.
Continuing to develop the API I have mentioned in previous posts, I have come across the following situation:
I need to be able to access a list of responses returned by the
webservice.
Problem is I am unsure how to implement IEnumerable on this class.
...
public class ResponseBodyResponse
{
public ResponseListResponse ResponseList { get; set; }
public class ResponseListResponse
{
public ResponseInfoResponse ResponseInfo { get; set; }
public class ResponseInfoResponse
{
public string RequestId { get; set; }
public string RequestType { get; set; }
public DateTime RequestDate { get; set; }
public string RequestStatus { get; set; }
public string Error { get; set; }
public string Memo { get; set; }
}
public ResponseListResponse()
{
ResponseInfo = new ResponseInfoResponse();
}
}
public ResponseBodyResponse()
{
ResponseList = new ResponseListResponse();
}
...
Before anyone asks I did get a copy of the xsd files, however generating the classes using xsd.exe resulted in a ridiculous mishmash of files with conflicting class names causing over 1000 ambiguous naming errors.
You really should return a concrete collection such as a list or an array from a web service instead of an implementation IEnumerable<T>, even though lists and arrays (and other colections) do implement it. Its not IEnumerable<T> that is the key for the serialization.
Aside, the nested class structure makes your code hard to consume.
Since I'm not sure of your intent with your above code, here is an example
public class Road
{
public Car[] Cars { get; set; } // this can be also `List<Car>`
}
public class Car
{
// stuff
}
I use classes to respond to PageMethods in some webpages. Asp.net engine automatically serializes the Class to JSON. I have few classes that have common properties like "RequestState"-Enum and "Error"-String which represent the State of the Request and the String describing the Error if any. For example look into this class below,
public class Contacts
{
public string Name { get; set; }
public string Country { get; set; }
public RequestState RequestState { get; set; }
public string Message { get; set; }
}
last two properties come in more than 4-5 classes. How do i abstract these properties so that they become common instead of declaring them in each class like how i do now. Interface could be possible i would like your ideas too for this, code snippet would be highly appreciated. thanks :)
public abstract class MessageBase
{
public RequestState RequestState { get; set; }
public string Message { get; set; }
}
public class Contacts : MessageBase
{
public string Name { get; set; }
public string Country { get; set; }
}
In the current system I'm working on I need to have functionality for ammendments.
That being that a user can create an ammendment package and that package contains new version of various domain objects (not structure changes just data changes).
I want to have an "AmmendmentPackage" that contains all of the ammendments that are to be made to various different types of elements.
So far I have
public class AmmendmentPackage : BaseObject
{
public string Name {get;set;}
public string Description { get; set; }
public int MajorVersionNumber { get; set; }
public int MinorVersionNumber { get; set; }
public bool IsGazetted { get; set; }
public AmmendmentPackageState State { get; set; }
}
public class Ammendment<T>
{
public T AmmendedElement{get;set;}
public AmmendmentState State {get;set;}
public ConcurrencyDetails ConcurrencyState { get; set; }
}
How do I go about having the AmmendmentPackage contain number of different Ammentments of various types. I was thinking about using ICollection but then I would have an ICollection<Ammenndment<T>> and I could only have one type of ammendment in the package.
Also was considering using a dictionary but not 100% sure how I would work that in just yet, hopefully I haven't missed something really basic but would appreciate some ideas.
Cheers
This is not possible.
You cannot have a strongly-typed collection that holds different types of objects.
Instead, you should make a non-generic base class or interface and make a collection of those.
You can create a collection of different concrete types that implement the same interface. If you make the interface definition empty, then it can even be applied to any reference type without modifying that type (but you'll have to figure out what operations are available on an AmmendedElement at runtime - I don't recommend this, it is just possible). For example:
using System;
using System.Collections.Generic;
public interface IAnyType { }
public abstract class PackageBase { }
public class Class_1 : IAnyType { public string Class_1_String { get; set; } }
public class Class_2 : IAnyType { public string Class_2_String { get; set; } }
public class AmmendmentPackage : PackageBase
{
public IList<Ammendment<IAnyType>> Ammendments { get; set; }
}
public class Ammendment<T> where T : IAnyType
{
public T AmmendedElement { get; set; }
}
class Program
{
static void Main(string[] args)
{
Ammendment<IAnyType> ammendment_1 = new Ammendment<IAnyType>();
ammendment_1.AmmendedElement = new Class_1();
Ammendment<IAnyType> ammendment_2 = new Ammendment<IAnyType>();
ammendment_2.AmmendedElement = new Class_2();
AmmendmentPackage package = new AmmendmentPackage();
package.Ammendments = new List<Ammendment<IAnyType>>(2);
package.Ammendments.Add(ammendment_1);
package.Ammendments.Add(ammendment_2);
}
}