Class with many inheriting class with one generic list - c#

I have a class
public class BaseHeaderFooterItem
{
public string Title { get; set; }
public string EnTitle { get; set; }
public HyperLink Link { get; set; }
public int Level { get; set; }
public HyperLink MobileLink { get; set; }
}
Many other class inherit from him
I want to have on generic list in the class BaseHeaderFooterItem
that will be able to hold a list from any type of the inherited classes.
something like this:
public class BaseHeaderFooterItem
{
public string Title { get; set; }
public string EnTitle { get; set; }
public HyperLink Link { get; set; }
public int Level { get; set; }
public HyperLink MobileLink { get; set; }
public List<T> Descendants { get; set; }
}
How can I do it ?

You could try to keep a properties to hold a child collection of the base type.
public class BaseHeaderFooterItem
{
public string Title { get; set; }
public string EnTitle { get; set; }
public HyperLink Link { get; set; }
public int Level { get; set; }
public HyperLink MobileLink { get; set; }
// here you can add instances of BaseHeaderFooterItem and any inherits type
public List<BaseHeaderFooterItem> Descendants { get; set; }
}
And you could add any tpe that inherits from BaseHeaderFooterItem, for sample:
var list = new List<BaseHeaderFooterItem>();
list.Add(new BaseHeaderFooterItem() {
Title = "Test"
Descendants = new List<BaseHeaderFooterItem>()
{
new ChildHeaderFooterItem() { /* properties */}
}
});
Or if you need a specif type for each BaseHeaderFooterItem, than try to specif the generic on the declaration.
public class BaseHeaderFooterItem<T>
where T : BaseHeaderFooterItem<T>
{
public string Title { get; set; }
public string EnTitle { get; set; }
public HyperLink Link { get; set; }
public int Level { get; set; }
public HyperLink MobileLink { get; set; }
// only T types
public List<T> Descendants { get; set; }
}
var list = new List<BaseHeaderFooterItem<ChildType>>();
list.Add(new BaseHeaderFooterItem() {
Title = "Test"
Descendants = new List<ChildType>()
{
new ChildHeaderFooterItem() { /* properties */}
}
});

You may use this pattern
public interface IBaseHeaderFooterItem
{
string Title { get; set; }
string EnTitle { get; set; }
public HyperLink Link { get; set; }
int Level { get; set; }
HyperLink MobileLink { get; set; }
}
public abstract class BaseHeaderFooterItem<T> : IBaseHeaderFooterItem
where T : IBaseHeaderFooterItem
{
public List<T> Descendants { get; set; }
public abstract string Title { get; set; }
public abstract string EnTitle { get; set; }
public abstract HyperLink Link { get; set; }
public abstract int Level { get; set; }
public abstract HyperLink MobileLink { get; set; }
}
Then you can inherit from BaseHeaderFooterItem<T> and T is constraint to be a class implementing IBaseHeaderFooterItem and having all those properties.

Related

Reuse DTO with different child/nested object

Imagine I have two DTOs that share top level types (ServerResponseDTO, ServerCallDetails) but the Items object has different child object (ItemsOfTypeA vs ItemsOfTypeB). What would be the best way to reuse defined top level classes without code duplication? - how can I easily instantiate next objects for ItemsOfTypeC, D and so on.
DTO 1:
public class ServerResponseDTO
{
public int CallId { get; set; }
public ServerCallDetails Details { get; set; }
}
public class ServerCallDetails
{
public int Id { get; set; }
public Items Items { get; set; }
}
public class Items
{
public int Id { get; set; }
public ItemsOfTypeA Items { get; set; }
}
DTO 2:
public class ServerResponseDTO
{
public int CallId { get; set; }
public ServerCallDetails Details { get; set; }
}
public class ServerCallDetails
{
public int Id { get; set; }
public Items Items { get; set; }
}
public class Items
{
public int Id { get; set; }
public ItemsOfTypeB Items { get; set; }
}
but is there a way without passing T to very bottom object?
No. Imagine you could write the following:
public class Items
{
public int Id { get; set; }
public T Items<T> { get; set; }
}
What would be the type of the foo variable in the following code?
var items = new Items();
var foo = pair.Items;
So you have to declare type where your Items<T> is used:
public class ServerResponseDTO<T>
{
public int CallId { get; set; }
public ServerCallDetails<T> Details { get; set; }
}
public class ServerCallDetails<T>
{
public int Id { get; set; }
public Items<T> Items { get; set; }
}
public class Items<T>
{
public int Id { get; set; }
public T FooBar { get; set; }
}
I.e. one of the solution might be to use generic type as Items property so now I can easily create new DTO like: ServerResponseDTO<ItemOfTypeC>
public class ServerResponseDTO<T>
{
public int CallId { get; set; }
public ServerCallDetails<T> Details { get; set; }
}
public class ServerCallDetails<T>
{
public int Id { get; set; }
public Items<T> Items { get; set; }
}
public class Items<T>
{
public int Id { get; set; }
public T Items { get; set; }
}

DynamoDB how to use ScanAsync on a nested structure?

Anyone have any idea / example how can I get the list of DynamoDbRepo with all nested structure if in DynamoDbMethodParameter.Name == specific value?
I suppose I should use ScanAsync but with what setting( ScanRequest ) ?
[DynamoDBTable("REPO_TABLE")]
public class DynamoDbRepo
{
[DynamoDBProperty("Id")]
[DynamoDBHashKey]
public int Id { get; set; }
[DynamoDBProperty("Solutions")]
public List<DynamoDbSolution> Solutions { get; set; }
}
public class DynamoDbSolution
{
[DynamoDBProperty("Path")]
public string Path { get; set; }
[DynamoDBProperty("Methods")]
public List<DynamoDbMethod> Methods { get; set; }
}
public class DynamoDbMethod
{
[DynamoDBProperty("Name")]
public string Name { get; set; }
[DynamoDBProperty("MethodParameters")]
public List<DynamoDbMethodParameter> MethodParameters { get; set; }
}
public class DynamoDbMethodParameter
{
[DynamoDBProperty("Type")]
public string Type { get; set; }
[DynamoDBProperty("Name")]
public string Name { get; set; }
}

How do I deserialize JSON correctly in C#

I am trying to deserialize the Supreme New York JSON but I am getting an error.
I used json2csharp.com to convert the Json into classes.
Then I summarised them all into one called items
namespace SUPBOTTESTING
{
public class items
{
public string name { get; set; }
public int id { get; set; }
public string image_url { get; set; }
public string image_url_hi { get; set; }
public int price { get; set; }
public int sale_price { get; set; }
public bool new_item { get; set; }
public int position { get; set; }
public string category_name { get; set; }
public int price_euro { get; set; }
public int sale_price_euro { get; set; }
}
}
using System;
using System.Net;
using System.Web.Script.Serialization;
namespace SUPBOTTESTING
{
class Program
{
public static void Main()
{
{
string shop_json = new WebClient().DownloadString("https://www.supremenewyork.com/mobile_stock.json");
JavaScriptSerializer shop_object = new JavaScriptSerializer();
items[] shirt_stock = shop_object.Deserialize<items[]>(shop_json);
Console.WriteLine(shirt_stock[1]);
}
}
}
}
I am getting the error:
Default constructor not found for type SUPBOTTESTING.items[]
Ok here is the solution. You have the correct idea but you need to understand the structure of your Json data.
You are deserializing it into an array of Object whereas your Json data returned itself is not an Array or a List. It contains child nodes that are an array so you need to structure your Object accordingly to get a successful breakdown of data.
Here I have used Newtonsoft to deserialise the Json data into an Object.
I have tested the code and it returns a list of Shirts
static void Main(string[] args)
{
var shop_json = new WebClient().DownloadString("https://www.supremenewyork.com/mobile_stock.json");
var shirt_stock = JsonConvert.DeserializeObject<StockObject>(shop_json);
// Picking shirts to demonstrate how to display values for all shirts
var shirts = shirt_stock.products_and_categories.Shirts;
foreach (var shirt in shirts)
{
var shirtBuilder = new StringBuilder();
shirtBuilder.AppendLine($"Name: {shirt.name}");
shirtBuilder.AppendLine($"ID: {shirt.id.ToString()}");
shirtBuilder.AppendLine($"New Item: {shirt.new_item.ToString()}");
shirtBuilder.AppendLine($"Category Name: {shirt.category_name}");
Console.WriteLine(shirtBuilder);
}
}
public class StockObject
{
public ProductsCats Products_and_categories { get; set; }
}
public class ProductsCats
{
public Details[] Shirts { get; set; }
public Details[] Bags { get; set; }
public Details[] Accessories { get; set; }
public Details[] Pants { get; set; }
public Details[] Jackets { get; set; }
public Details[] Skates { get; set; }
public Details[] Hats { get; set;}
public Details[] Sweatshirts { get; set;}
[JsonProperty("Tops/Sweaters")]
public Details[] TopsSweaters { get;set;}
public Details[] New { get; set; }
}
public class Details
{
public string name { get; set; }
public int id { get; set; }
public string image_url { get; set; }
public string image_url_hi { get; set; }
public int price { get; set; }
public int sale_price { get; set; }
public bool new_item { get; set; }
public int position { get; set; }
public string category_name { get; set; }
public int price_euro { get; set; }
public int sale_price_euro { get; set; }
}
You see what I have done here?
So your Json data contains a parent node products_and_categories and its child node contains an array of Shirts which is what you are after?
StockObject class contains the Parent property called Products_and_categories of type object ProductsCats.
ProductsCats Object contains the property Shirts of type Details which is an array and will be used during the deserialising process.
Hope this helps?
Well you do not need to specify a default constructor. What is wrong is, i think you didn't check the json data properly. Because your items class is not in the first level of json. You need to create a couple of classes to be more accurate on deserializing.
First of all you need to know that this json file has a lot of bad-smells and bad-practices on it.
Note that you need to install Newtonsoft.Json before going further. It is much more convenient way to deserialize a json into C# classes.
Yet, i wrote a proper way of deserializing it:
public class BaseItem
{
public string Name { get; set; }
public int Id { get; set; }
public string Image_url { get; set; }
public string Image_url_hi { get; set; }
public int Price { get; set; }
public int Sale_price { get; set; }
public bool New_item { get; set; }
public int Position { get; set; }
public string Category_name { get; set; }
public int Price_euro { get; set; }
public int Sale_price_euro { get; set; }
}
public class Shirt : BaseItem { }
public class Bag : BaseItem { }
public class Accessory : BaseItem { }
public class Pant : BaseItem { }
public class Jacket : BaseItem { }
public class Skate : BaseItem { }
public class Hat : BaseItem { }
public class Sweatshirt : BaseItem { }
public class TopsSweater : BaseItem { }
public class New : BaseItem { }
public class RootObject
{
public List<object> Unique_image_url_prefixes { get; set; }
public ProductsAndCategories Products_and_categories { get; set; }
public string Release_date { get; set; }
public string Release_week { get; set; }
}
public class ProductsAndCategories
{
public List<Shirt> Shirts { get; set; }
public List<Bag> Bags { get; set; }
public List<Accessory> Accessories { get; set; }
public List<Pant> Pants { get; set; }
public List<Jacket> Jackets { get; set; }
public List<Skate> Skate { get; set; }
public List<Hat> Hats { get; set; }
public List<Sweatshirt> Sweatshirts { get; set; }
[JsonProperty("Tops/Sweaters")]
public List<TopsSweater> TopsSweaters { get; set; }
public List<New> New { get; set; }
}
First of all, all of your items are have the same properties on them, yet, they all marked as different properties. So that, i created a BaseItem class and other empty classes which are inherited from that.
Also you need other 2 classes -which are RootObject and ProductsAndCategories- to provide data on them. Note that there is a JsonProperty("blabla") on the TopsSweaters property. Because, in json file it is Tops/Sweaters, and you can not use that name on a C# property. That is the attribute for using that kind of different property names.
Then you can populate your object like this:
static void Main(string[] args)
{
var jsonData = "https://www.supremenewyork.com/mobile_stock.json";
string shopJson = new WebClient().DownloadString(jsonData);
RootObject shirtStock = JsonConvert.DeserializeObject<RootObject>(shopJson); //All json data is in this variable
Console.WriteLine(shirtStock.Products_and_categories.Shirts[1]);
}
Your problem is that youre using a class to load the JSON data in, where you should use a struct, alternatively you can also create a constructor that takes no arguments and sets all variables to default values, which is a lot of work so just replace class with struct:
public struct Items
{
public string Name { get; set; }
public int Id { get; set; }
public string Image_Url { get; set; }
public string Image_Url_Hi { get; set; }
public int Price { get; set; }
public int Sale_Price { get; set; }
public bool New_item { get; set; }
public int Position { get; set; }
public string Category_Name { get; set; }
public int Price_Euro { get; set; }
public int Sale_Price_Euro { get; set; }
}
Also please stick to C# naming conventions, you should be able to do this since most JSON parsers are case insensitive by default.
Some more info: A class doesnt really has a proper default constructor if you dont define one, where as a struct always has a default constructor, so when the JSON parser wants to init your class it cant because a default constructor isnt definded.
static void Main(string[] args)
{
string shop_json = new WebClient().DownloadString("https://www.supremenewyork.com/mobile_stock.json");
JavaScriptSerializer shop_object = new JavaScriptSerializer();
var shirt_stock = shop_object.Deserialize<NewYarkItems>(shop_json);
var v = shirt_stock;
}
public class NewYarkItems
{
public dynamic unique_image_url_prefixes { get; set; }
public products_and_categories products_And_Categories { get; set; }
public string release_date { get; set; }
public string release_week { get; set; }
}
public class products_and_categories
{
public List<items> Jackets { get; set; }
}
public class items
{
public string name { get; set; }
public int id { get; set; }
public string image_url { get; set; }
public string image_url_hi { get; set; }
public int price { get; set; }
public int sale_price { get; set; }
public bool new_item { get; set; }
public int position { get; set; }
public string category_name { get; set; }
public int price_euro { get; set; }
public int sale_price_euro { get; set; }
}

Add different attributes to derived classes #

I have a base class named event and 2 subclasses named sendEvent and receiveEvent. You can see the code below:
namespace App
{
public class Event
{
public Type type { get; set; }
public Details details { get; set; }
}
public class Details
{
public string timestamp { get; set; }
public string reference { get; set; }
public string id { get; set; }
public string correlator { get; set; }
public string device1 { get; set; }
public string device2 { get; set; }
public string device3 { get; set; }
}
public class Details
{
public string timestamp { get; set; }
public string reference { get; set; }
public string primaryid { get; set; }
public string primary_correlator { get; set; }
public string secondaryid { get; set; }
public string secondary_correlator { get; set; }
public string device4 { get; set; }
public string device5 { get; set; }
}
class ReceiveEvent : Event
{
public ReceiveEvent()
{
this.type = Type.Recieve;
}
}
class SendEvent : Event
{
public SendEvent()
{
this.type = Type.Send;
}
}
public enum Type
{
Send,
Receive
}
}
I want that the sendEvent use first details while the receiveEvent use second details class. I couldn't figure out how can I make it possible. Do you have any thoughts?
One option would be to separate the common fields into a base class and create subclasses:
public class Details
{
public string timestamp { get; set; }
public string reference { get; set; }
}
public class SendDetails : Details
{
public string id { get; set; }
public string correlator { get; set; }
public string device1 { get; set; }
public string device2 { get; set; }
public string device3 { get; set; }
}
public class ReceiveDetails : Details
{
public string primaryid { get; set; }
public string primary_correlator { get; set; }
public string secondaryid { get; set; }
public string secondary_correlator { get; set; }
public string device4 { get; set; }
public string device5 { get; set; }
}
Then make your Event classes generic:
public class Event<TDetail> where TDetail : Details
{
public Type type { get; set; }
public TDetail details { get; set; }
}
public class ReceiveEvent : Event<ReceiveDetails>
{
public ReceiveEvent()
{
this.type = Type.Recieve;
}
}
public class SendEvent : Event<SendDetails>
{
public SendEvent()
{
this.type = Type.Send;
}
}
That way you can access details in a strongly-typed manner from either the base event class or the subclasses.
You can create a base class Details and derive subclasses like SendDetails and ReceiveDetails from it:
namespace App
{
public class Event
{
public Type type { get; set; }
public Details details { get; set; }
}
public class Details
{
public string timestamp { get; set; }
public string reference { get; set; }
}
public class SendDetails : Details
{
public string id { get; set; }
public string correlator { get; set; }
public string device1 { get; set; }
public string device2 { get; set; }
public string device3 { get; set; }
}
public class ReceiveDetails : Details
{
public string primaryid { get; set; }
public string primary_correlator { get; set; }
public string secondaryid { get; set; }
public string secondary_correlator { get; set; }
public string device4 { get; set; }
public string device5 { get; set; }
}
class ReceiveEvent : Event
{
public ReceiveEvent()
{
this.type = Type.Recieve;
this.Details = new ReceiveDetails();
}
}
class SendEvent : Event
{
public SendEvent()
{
this.type = Type.Send;
this.Details = new SendDetails();
}
}
public enum Type
{
Send,
Receive
}
}
If you want to use single class Event you can use Generics:
public class Event<TDetails>
{
public Type type { get; set; }
public TDetails details { get; set; }
}
class SendEvent : Event<SendDetails>
{
public SendEvent()
{
this.type = Type.Send;
}
}

Passing interface based property to Web API

public interface ISurvey
{
List<ISurveyItem> Items { get; set; }
int QueueId { get; set; }
SurveyType Type { get; set; } //an enum
SurveyResult ToSurveyResult();
void CopyToSurveyDto(Survey dbsurvey);
}
public interface ISurveyItemBase
{
int Sequence { get; set; }
string Template { get; set; }
string Label { get; set; }
int Id { get; set; }
}
public interface ISurveyItem:ISurveyItemBase
{
SurveyItemType Type { get; set; }//an enum
string Value { get; set; }
}
public class Survey : ISurvey
{
public List<ISurveyItem> Items { get; set; }
public int QueueId { get; set; }
public SurveyType Type { get; set; }
public SurveyResult ToSurveyResult()
{
//implimentation
}
public void CopyToSurveyDto(Data.Survey dbsurvey)
{
//implimentation
}
}
When I try pass the Survey object via POST to my Web API service, the Items property is serialized to an empty list. I imagine this has to do with it not knowing what concrete type to serialize the items too. Are there any pointers on how to do this?
In order to accomplish this, I had to refactor a little bit:
public interface ISurvey<T>
where T: ISurveyItem
{
List<T> Items { get; set; }
int QueueId { get; set; }
SurveyType Type { get; set; }
}
public class Survey : ISurvey<SurveyItem>
{
public List<SurveyItem> Items { get; set; }
public int QueueId { get; set; }
public SurveyType Type { get; set; }
}
credit source

Categories

Resources