Creating class members during run time - C# - c#

I have a simple class defined like this:
public class StickColumns
{
public string wellname { get; set; }
public double WellLength { get; set; }
}
In the code, I get some data as list<double> perfdepth; assume this is perfdepth1,perfdepth2,perfdepth3. Of course, this list is dynamic hence, I wouldnt know beforehand to change my class definition to:
public class StickColumns
{
public string wellname { get; set; }
public double WellLength { get; set; }
public double perfdepth1 { get; set; }
public double perfdepth2 { get; set; }
public double perfdepth3 { get; set; }
}
Can these new members be created during run time?
The reason why I think I would need this is because of data binding in WPF. Eventually I need to display "point series"; Perfdepth1 as one series, perfdepth2 as another series and so on, i.e, dynamic number of Perfdepths.
If there is a simpler way to do it, I am all ears!

You might just want to use the dynamic type with ExpandoObject..
dynamic stickColumns = new ExpandoObject();
stickColumns.wellName = "Something";
stickColumns.perfdepth1 = "Something Else";
It has its drawbacks as it does mean you end up with runtime errors etc... but it can be useful for this type of scenario.

Related

Send a limited/reduced class to frontend

What I want
I want to send a limited/reduced class/object to frontend (as JSON). I use .NET Core 5.
What I have
I have a model class like this:
namespace Tasks.Models
{
public class Resources
{
public Guid Id { get; set; }
public string Type { get; set; }
public string Url { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public DateTime? Createdon { get; set; }
public Guid Userid { get; set; }
public Guid Taskid { get; set; }
public int Clicked { get; set; }
public byte Active { get; set; }
+++ many more properties
}
}
Now depending on the which controller that calls this model I want to have different "kind" of models. So if the resource is file I maybe want the properties Id,Type,Name. But if the resource is URL I want Id, Url, Name.
I tried setting up a method that "initialized the fields I wanted, but that also returned all properties
public static Responses FileResponse()
{
var response = new Responses()
{
Id = new Guid(),
Name = "",
Type = "File",
};
return response;
}
Now, when I call the Resources class or this method I get all properties, and returning it to the view presents all properties, but mostly as null, because I only set the three fields in the method.
What is the recommended way of solving this?
If you want to remove the field if it's null instead of showing in json with null value.
public class Resources
{
public Guid Id { get; set; }
public string Type { get; set; }
// if null, dont show it in JSON output
[JsonIgnoreAttribute(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string Url { get; set; }
// if null, dont show it in JSON output
[JsonIgnoreAttribute(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string Name { get; set; }
public string Description { get; set; }
public DateTime? Createdon { get; set; }
public Guid Userid { get; set; }
public Guid Taskid { get; set; }
public int Clicked { get; set; }
public byte Active { get; set; }
}
PS: Fiddle https://dotnetfiddle.net/hiMAci
It is just limiting the Resource class I am not able to do
Yep, side effect of C# being strongly typed, with object X definitely having properties Y and Z. You need differently shaped objects - either full on classes or records - that name the reduced set of properties because the serializer is going to look a tthe object and ser every property it can find.
You could make a new class for every variation - quick and easy with records, and easy to pass around inside your C#:
public record FileThing(string Id, string Type, string Name);
//make a new one and return it
new FileThing(someResources.Id, someResources.Type, someResources.Name);
Or can consider using an anonymous type if you're literally looking to put a few properties into some json, down a socket to a consuming front end (I can't quite decide what you mean by "view" - it doesn't seem to be an MVC View) that only cares about a few props out of many
So if the resource is file I maybe want the properties Id,Type,Name. But if the resource is URL I want Id, Url, Name.
public ActionResult SomeControllerMethod(){
if(isFile)
return Ok(new { someResources.Id, someResources.Type, someResources.Name });
else if(isUrl)
return Ok(new { someResources.Id, someResources.Url, someResources.Name });
}
Anonymous types are a bit harder to work with because the compiler writes the class for you, so it's tricky to do things like declare return types from methods if the method is returning an AT.. But if you're using it as some fill-in all within one method, such as a "make this and serialize it", they work well..
I think your approach is not the right one here. I tend to follow more general OO guidelines in this situation (note, some consider these a bit dated, and other solutions exist. But they are still commonly used)
You write against an interface. So let's see what you want... A guid, type and name. All other deatils aren't important.
public interface IResourceDetails
{
public Guid Id { get; }
public string Name { get; }
public string Type { get; }
}
And you can have multiple of these interfaces.
You could then implement the interfaces per type. But I would probably combine them in a base class
public abstract class ResourceBase : IResourceDetails
{
public Guid Id { get; } = new ();
public string Name { get; init; }
public string Type { get; }
public ResourceBase(string type)
{
Type = type;
}
}
Each resource type would have it's own implementation
public class FileResource : ResourceBase
{
public FileResource() : base("File") { }
// File-specific properties.
public string Description { get; init; }
public DateTime? Createdon { get; init; }
}
The response method then could be made generic and look like this
public static IActionResult Response(IResourceDetails resource)
{
return Ok(new
{
resource.Id,
resource.Name,
resource.Type,
});
}

How to store and sort two types of classes in List<>?

I have two classes:
public class SavedQuote
{
public int ID { get; set; }
public string Text { get; set; }
public string Context { get; set; }
public string URL { get; set; }
public string Comment { get; set; }
public string WhereToSearch { get; set; }
public DateTime DateOfAdding { get; set; }
public string OwnerName { get; set; }
public virtual ICollection<Tag> Tags { get; set; }
}
public class NoteOnSite
{
public int ID { get; set; }
public string URL { get; set; }
public DateTime DateOfAdding { get; set; }
public string OwnerName { get; set; }
public string Comment { get; set; }
public virtual ICollection<Tag> Tags { get; set; }
}
I have also two lists: one that represents some "SavedQuotes" and one that has some "NoteOnSites". I need to sort data from those Lists by DateOfAdding and display them in one table on my webiste.
The problem is: I (probably) can't save objects with two different classes in one List<> (I need to do this to sort those objects). What do you advise me to do? How would you solve this problem?
I (probably) can't save objects with two different classes in one List<>
You can, as long as object have a common base class. In C#, all objects have a common base class System.Object, which is enough to store objects of entirely different types in a single list.
A heavyweight approach would be to put a common interface on the objects that you wish to sort:
public interface IWithDate {
public DateTime DateOfAdding { get; set; }
}
public class SavedQuote : IWithDate {
...
}
public class NoteOnSite : IWithDate {
...
}
...
var mixedList = new List<IWithDate>();
However, this may introduce more structure than you wish: making the classes related to each other through a common interface is too much, if all you need is to sort objects of these classes together.
If you wish to sort the objects on a commonly named property without adding any static structure around your classes, you can make a list of dynamic objects, and use DateOfAdding directly:
var mixedList = new List<dynamic>();
mixedList.AddRange(quotes);
mixedList.AddRange(notes);
mixedList.Sort((a, b)=>a.DateOfAdding.CompareTo(b.DateOfAdding));
Try a little Linq using JOIN
List<SavedQuote> savedQuotes = new List<SavedQuote>();
List<NoteOnSite> noteOnSites = new List<NoteOnSite>();
var results = from savedQuote in savedQuotes.OrderBy(x => x.DateOfAdding)
join noteOnSite in noteOnSites.OrderBy(x => x.DateOfAdding)
on savedQuote.ID equals noteOnSite.ID
select new { saved = savedQuotes, note = noteOnSites };​

class for this JSON

I am hitting an API that returns some JSON as follows:
{"stats":{"X":{"Name":"X","Found":"Yes"}},"response":"OK","runtimeMs":798}
I would like to generate C# classes for it and I used json2sharp, it generated classes such as root object which i modified as follows:
public class RootObject
{
public Stats stats { get; set; }
public string response { get; set; }
public int runtimeMs { get; set; }
}
public class Stats
{
public string name { get; set; }
}
public class Variant
{
public string name { get; set; }
public string Found { get; set; }
}
The issue i am facing is that in the class Stats I have used name since the json will reply with any name such as X or Y or Z.
I am able to deserialise the JSON into the root object but cannot get any data into the stats class.
JsonConvert.DeserializeObject<RootObject>(response.Content);
Any ideas why i might be doing incorrectly?
Your problem is similar to this How can I parse a JSON string that would cause illegal C# identifiers?
So, your model should be
public class Variant
{
public string Name { get; set; }
public string Found { get; set; }
}
public class RootObject
{
public Dictionary<string, Variant> stats { get; set; }
public string response { get; set; }
public int runtimeMs { get; set; }
}
EDIT
#evanmcdonnal if use a dictionary as shown in the EZI's answer or an object with fields named X, Y, and Z you have to perform nullity or keyexists checks all over the place in order to safely use the object.
I don't think this simple linq is hard to write
rootObj.stats.Values.Where(....);
or
rootObj.stats.Keys.Select(....);
That is happening because json.NET is looking for a property name in your class which matches the field name in the json. Since name does not resemble anything in the json it finds nothing.
There are a couple of options for how to work around this. You can use an annotation to say what the json field you want to put there is, or you can change the name of the property. However, from you post it sounds like you're saying there could be an object called X or an object called Y in the json, neither of those options will make that deserialize correctly in all cases. I'll edit with some ideas for how you may want to handle that.
Based on OP's comment, here's what you're looking for;
public class RootObject
{
public Stats stats { get; set; }
public string response { get; set; }
public int runtimeMs { get; set; }
}
public class Stats
{
public Varient X { get; set; }
public Varient Y { get; set; }
public Varient Z { get; set; }
}
public class Variant
{
public string name { get; set; }
public string Found { get; set; }
}
In other places in your code you just have to have two code paths or do a conversion to avoid doing nullity checks everywhere.
if (myInstance.X != null)
// it was X that was in the json
else if (myInstace.Y != null)
// it was Y
else
// not sure what happened, perhaps neither X nor Y were present.
Now the other option is to make this just an intermediary then you define another type that just has one property named name and you give it a constructor that takes a RootObject and assigns whichever value isn't null to it's name property or whatever you want to call it. I would probably do something like this myself because if use a dictionary as shown in the EZI's answer or an object with fields named X, Y, and Z you have to perform nullity or keyexists checks all over the place in order to safely use the object.

WP8 JSON Deserialisation of Arrays nested in Arrays nested in Arrays

I want to do something quite simple.
I just want to take a JSON string (which I have) and populate a whole bunch of stuff with it.
The problem for me is that there are arrays hidden in array inside more arrays, and I can't get at my data.
I tried standard deserialization like so ...
var apiData = JsonConvert.DeserializeObject<RootObject>(json);
But this only lets me get into the top layer - what is in rootObject
I tried making a dictionary ...
Dictionary<string, dynamic> values = JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(json);
but that doesn't let me drill down either (or I can't make it).
I have set up my c# using json2c#
I've been all over the internet including here.
The closest I have got to creating anything close is an expandoObject
var converter = new ExpandoObjectConverter();
dynamic obj = JsonConvert.DeserializeObject<ExpandoObject>(json, converter);
which I can see from the debugger is keeping everything structured as I would like but I've no idea how to get some of the stuff out.
Long story short, its been two days now and I'm bashing my head against a brick wall.
I just want to be able to get the data out of the JSON string and I can't change that string as its not mine.
public class NewsArticlesList
{
public string title { get; set; }
public string link { get; set; }
public string source { get; set; }
public string snippet { get; set; }
}
public class jobsList
{
public string title { get; set; }
public string titleLinkUrl { get; set; }
public List<object> relatedSearchesList { get; set; }
public string formattedTraffic { get; set; }
public int trafficBucketLowerBound { get; set; }
public int interestLevel { get; set; }
public string interestColor { get; set; }
public List<NewsArticlesList> newsArticlesList { get; set; }
public double startTime { get; set; }
public string shareUrl { get; set; }
public string date { get; set; }
}
public class jobsByDateList
{
public string date { get; set; }
public string formattedDate { get; set; }
public List<jobsList> jobsList { get; set; }
}
public class RootObject
{
public string summaryMessage { get; set; }
public double dataUpdateTime { get; set; }
public List<jobsByDateList> jobsByDateList { get; set; }
public string oldestVisibleDate { get; set; }
public bool lastPage { get; set; }
}
My problem is these lists inside lists inside lists.
I can get to jobsListByDate.formattedDate but I can't get anywhere near jobsListByDate.jobsList.titleLinkUrl let alone inside the NewsArticlesList to those sources.
Apologies if this is super-easy (I hope it is) but I'm a WP8 noob.
I know there are similar threads on SO, but none of them seem to deal with such deep arrays.
I was not stipulating which branch to go down and so it was confused.
System.Diagnostics.Debug.WriteLine(apiData.jobsByDateList[0].jobsList[0].interestLevel);
I was trying to get in using
System.Diagnostics.Debug.WriteLine(apiData.jobsByDateList.jobsList.interestLevel);
and intellisense was freaking out.
With the [0] I'm now able to drill in just fine and don't need the expandoobject. Just needed to sleep on it. :-)

class design: How do I create a class with nested objects?

I am currently developing a client library for connecting to Newegg using the documentation provided by Newegg and have a question on class design.
In working with various API's ( namely NetSuite and Amazon's MWS ) I come across classes that have are used like this:
recToFulfill.packageList = new ItemFulfillmentPackageList();
recToFulfill.packageList.package = new ItemFulfillmentPackage[ifitemlist.item.Length];
recToFulfill.packageList.package[i] = new ItemFulfillmentPackage();
recToFulfill.packageList.package[i].packageWeightSpecified = true;
recToFulfill.packageList.package[i].packageTrackingNumber = "trackingNumber";
The question I have is: How do I properly design the nested objects like above? I have never had to worry about this previously, so I am unsure on where to look, or start.
The bit I need to figure out looks like this ( taken from the API documentation provided):
<UpdateOrderStatusInfo>
<IsSuccess></IsSuccess>
<Result>
<OrderNumber></OrderNumber>
<SellerID></SellerID>
<OrderStatus></OrderStatus>
</Result>
</UpdateOrderStatusInfo>
All fields are type string, except order number which is an integer.
I have this currently:
public class UpdateOrderStatusInfo
{
public string IsSuccess { get; set; }
public int OrderNumber { get; set; }
public string SellerID { get; set; }
public string OrderStatus { get; set; }
}
But the returned XML Response has Results as a parent node which to me seems like it should be represented within the class itself. Would I just do this?
public UpdateOrderStatusInfo results {get; set;}
If so, where do the child nodes go?
What I need is to be able to say is something like:
UpdateOrderStatusInfo updateInfo = new UpdateOrderStatusInfo();
if(updateInfo.IsSuccess.Equals("true")
{
Console.WriteLine(updateInfo.Results.OrderStatus);
}
Any help, or advice on where to get this information is appreciated.
Easy breezy. If it has no children, it's a scalar property. If it does, it is its own class, and referenced in the parent class accordingly. If it repeats, it's a collection, and is referenced like a class (these are complex type, not primitives). Make sure you initialize them in your constructors).
class Program
{
static void Main(string[] args)
{
var myOrder = new UpdateOrderStatusInfo();
myOrder.IsSuccess = "true";
myOrder.OrderResult.OrderNumber = 1001;
myOrder.OrderResult.OrderStatus = "Pending";
myOrder.OrderResult.SellerID = "69";
}
}
public class UpdateOrderStatusInfo
{
public string IsSuccess { get; set; }
public Result OrderResult { get; set; }
public UpdateOrderStatusInfo()
{
OrderResult = new Result();
}
}
public class Result
{
public int OrderNumber { get; set; }
public string SellerID { get; set; }
public string OrderStatus { get; set; }
}
You need to define the Result as a separate class, called whatever you want, then add a Result property as that type. The Result class can be defined at the namespace level, or, if you are unlikely to use it anywhere else on its own, you can nest the class definition inside the UpdateOrderStatusInfo class:
public class UpdateOrderStatusInfo
{
public class UpdateOrderResult
{
public int OrderNumber { get; set; }
public string SellerID { get; set; }
public string OrderStatus { get; set; }
}
public UpdateOrderStatusInfo()
{
Result = new UpdateOrderResult();
}
public string IsSuccess { get; set; }
public UpdateOrderResult Result { get; set; }
}
The easy way is to use the xsd.exe tool.
The command xsd response.xml will generate the file response.xsd
The command xsd response.xsd /C will generate the file response.cs which contains the classes necessary to serialize/deserialize the xml posted.

Categories