I have a Dictionary<string, XMLMessage> where XMLMessage is a struct:
private struct XMLMessage
{
public string Message { get; set; }
public DateTime TimeRead { get; set; }
}
I will use the Dictionary similar to this:
storedMessages["1X"] = new XMLMessage() { Message = "<XML>1X</XML>", TimeRead = DateTime.Now };
storedMessages["1Y"] = new XMLMessage() { Message = "<XML>1Y</XML>", TimeRead = DateTime.Now };
There will be a gap in seconds between the the dictionary object assigning a value hence the DateTime object.
At some point I need to keep the keys in the Dictionary but the oldest value to be set to empty.
I have tried this but don't seem to have got it quite right.
storedMessages.Where(x => x.Key.Contains("1")).OrderBy(s => s.Value.TimeRead).Skip(1)
Thanks
UPDATE: I think I can do something like this but wanted to get your opinions
var j = storedMessages.Where(x => x.Key.Contains("1")).OrderByDescending(s => s.Value.TimeRead).First().Key;
storedMessages[j] = new XMLMessage();
Yes, your updated version looks okay - although I'd say you'd be better off storing a list in time order as well as the dictionary, to make life easier.
I would strongly discourage you from using mutable structs though. Either use a class, or change the struct to be immutable.
Example of making it a class:
private class XmlMessage
{
public string Message { get; set; }
public DateTime TimeRead { get; set; }
}
Example of making it an immutable struct:
private struct XmlMessage
{
private readonly string message;
private readonly DateTime timeRead;
public string Message { get { return message; } }
public DateTime TimeRead { get { return timeRead; } }
public XmlMessage(string message, DateTime timeRead)
{
this.message = message;
this.timeRead = timeRead;
}
}
Of course you could make it an immutable class instead...
Related
I have different classes sharing some properties of same type and name. I wish to assign same property values to each other. I explain my intention better in comments in the following pseudo-code. Is it possible in C#?
Ponder that there are a plethora of common properties but in unrelated classes, must we assign them one-by-one?
Second case is about sharing same properties but some of them may be nullable, who knows!
Side note: the classes already exist, cannot be altered, touched. Kinda sealed.
Can't it be done using nameofoperator and two for loops? Compare property names if matched, assign?
using System;
namespace MainProgram
{
class HomeFood
{
public DateTime Date { get; set; }
public string food1 { get; set; }
public string food2 { get; set; }
public int cucumberSize { get; set; }
}
class AuntFood
{
public string food2 { get; set; }
public int cucumberSize { get; set; }
public DateTime Date { get; set; }
public string food1 { get; set; }
// extra
public double? length { get; set; }
}
class GrandpaFood
{
public string? food2 { get; set; }
public int cucumberSize { get; set; }
public DateTime? Date { get; set; }
public string food1 { get; set; }
// extra
}
static class Program
{
public static void Main(string[] args)
{
var home = new HomeFood
{
Date = new DateTime(2020, 1, 1),
food1 = "cucumber",
food2 = "tomato",
cucumberSize = 123
};
var aunt = new AuntFood();
/*
First case: same types
Expected for-each loop
assigning a class's property values
to other class's property values
or for-loop no matter
foreach(var property in HomeFood's properties)
assign property's value to AuntFood's same property
*/
var home2 = new HomeFood();
var grandpa = new GrandpaFood
{
Date = new DateTime(2020, 1, 1),
food1 = "dfgf",
food2 = "dfgdgfdg",
cucumberSize = 43534
};
/*
Second case: similar to first case
with the exception of same type but nullable
or for-loop no matter
foreach(var property in GrandpaFood's properties)
assign property's value to GrandpaFood's same property
we don't care if it is null e.g.
Home2's same property = property's value ?? default;
*/
}
}
}
Based on the comments in the questions, this is just to show how it can be done with reflection.
Disclaimer, this is just a very simplified example on how to use reflection to sync properties. It does not handle any special cases (modifiers, read only, type mismatch, etc)
I would strongly suggest to use automapper to achieve the qp goals.
public class Type1
{
public string Property1 { get; set; }
public string Property2 { get; set; }
}
public class Type2
{
public string Property1 { get; set; }
public string Property3 { get; set; }
}
class Program
{
static void Main(string[] args)
{
var t1 = new Type1 { Property1 = "Banana" };
var t2 = new Type2();
var properties1 = typeof(Type1).GetProperties().ToList();
var properties2 = typeof(Type2).GetProperties().ToList();
foreach(var p in properties1)
{
var found = properties2.FirstOrDefault(i => i.Name == p.Name);
if(found != null)
{
found.SetValue(t2, p.GetValue(t1));
}
}
Console.WriteLine(t2.Property1);
}
}
The short answer is, apply OOP. Define a base Food class and inherit from it in any specific food classes you have. You can put all the shared props in the base class.
public class Food
{
public string food2 { get; set; }
// other shared stuff
}
class GrandpaFood : Food
{
// other specific stuff
}
As others have said, use some of the Object Oriented properties, like inheriting a super class of implement an interface.
In case you go for inheritance, consider making the super class (the one you inherit from) abstract. This means that the super class itself cannot be instantiated, which greatly reduces the risk of violating the Liskov Substitutional Principle. Also it often reflects the real problem better. In your example, this would also be the case, as “food” is not an actual thing in the real world, but rather a group of things.
This question is related to this question. I managed to get one step further, but I am now unable to initialize my whole object with default values in order to prevent it from being null at list level. The goal of this is to hand down the "null" values to my SQL query. Ultimately what I want is one record in my DB that will express: This row has been recorded, but the related values were "null".
I have tried Brian's fiddle and it does not seem to work for me to initialize the whole model with standard values.
Expectation: Upon object initialisation the "null" values should be used and then overwritten in case there is a value coming through JSON deserialisation.
Here is what I have tried. None of this will have the desired effect. I receive this error:
Application_Error: System.ArgumentNullException: Value cannot be null.
Every time I try to access one of the lists in the data model.
namespace Project.MyJob
{
public class JsonModel
{
public JsonModel()
{
Type_X type_x = new Type_X(); // This works fine.
List<Actions> action = new List<Actions>(); // This is never visible
/*in my object either before I initialise JObject or after. So whatever
gets initialised here never makes it to my object. Only Type_X appears
to be working as expected. */
action.Add(new Actions {number = "null", time = "null", station =
"null", unitState = "null"}) // This also does not prevent my
//JsonModel object from being null.
}
public string objectNumber { get; set; }
public string objectFamily { get; set; }
public string objectOrder { get; set; }
public string location { get; set; }
public string place { get; set; }
public string inventionTime { get; set; }
public string lastUpdate { get; set; }
public string condition { get; set; }
public Type_X Type_X { get; set; }
public List<Actions> actions { get; set; }
}
public class Actions
{
public Actions()
{
// None of this seems to play a role at inititialisation.
count = "null";
datetime = "null";
place = "null";
status = "null";
}
// public string count { get; set; } = "null"; should be the same as above
// but also does not do anything.
public string count { get; set; }
public string datetime { get; set; }
public string place { get; set; }
public string status { get; set; }
}
public class Type_X
{
public Type_X
{
partA = "null"; // This works.
}
public string partA { get; set; }
public string PartB { get; set; }
public string partC { get; set; }
public string partD { get; set; }
public string partE { get; set; }
}
}
This is how I now initialize the object based on Brian's answer.
JObject = JsonConvert.DeserializeObject< JsonModel >(json.ToString(), new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore});
When I try to iterate over Actions' content, it (logically) gives me above mentioned null error.
for (int i = 0, len = JObject.actions.Count(); i < len; i++)
My current understanding of constructor initialisations:
If I define values such as count = "null"; they should appear in any new object that is created.
If default values are present I would then also expect that a list that has items with default values (such as count for ex.) would be of Count() 1 and not null. How is that even possible?
This will get you out of your bind:
private List<Actions> _actions = new List<Actions>();
public List<Actions> actions { get => _actions; set => _actions = value ?? _actions; }
This causes trying to set actions to null to set it to the previous value, and it is initially not null so it can never be null.
I'm not absolutely sure I'm reading your question right, so here's the same fragment for partA:
private string _partA = "null";
public string partA { get => _partA; set => _partA = value ?? _partA; }
I have found that in some cases, initializing generic lists with their default constructor on your model increases ease of use. Otherwise you will always want to validate they are not null before applying any logic(even something as simple as checking list length). Especially if the entity is being hydrated outside of user code, i.e. database, webapi, etc...
One option is to break up your initialization into two parts. Part 1 being the basic initialization via default constructor, and part 2 being the rest of your hydration logic:
JObject = new List < YourModel >();
... < deserialization code here >
Alternatively you could do this in your deserialization code, but it would add a bit of complexity. Following this approach will allow you to clean up your code in other areas since each access will not need to be immediately proceeded by a null check.
By default, objects are passed by reference to methods. I know a way to make a clone of the object and pass it to the method like a deep copy.
Here's one implementation for above approach (serialize it and deserialize to a new object):
private static APIRateLimit DeepCopy(APIRateLimit source)
{
var DeserializeSettings = new JsonSerializerSettings { ObjectCreationHandling = ObjectCreationHandling.Replace };
return JsonConvert.DeserializeObject<APIRateLimit>(JsonConvert.SerializeObject(source), DeserializeSettings);
}
But, Is it the only way to do this? Is there any better approach for a scenario like this?
Note: I'm specific about the objects which contain primitives only without any readonly/constant modifiers.
Object is like this:
public class APIRateLimit
{
public int MaxAllowed { get; set; }
public int APICallDurationInSec { get; set; }
public string APIRateLimitInfo { get; set; }
public string ConnectionType { get; set; }
}
I have an object containing different properties like the object below:
public class CompressedLogResponse
{
public string LoggerType { get; set; }
public int NumberOfRegisters { get; set; }
public int NewLogId { get; set; }
public DateTime LoggerAnnounceTime { get; set; }
public List<Log> Log{ get; set; }
}
How can I return a List of this objekt that does not include the List<Log> Log property?
Linq would be preffered
Thanks for any help that you can provide
You cannot just hide a property of a class (you declared it a as public)
Option 1:
Althought as Robson wrote you can set it null (thats not very reliable thaught cause nobody expects a class containing a property that is always null)
Option2:
If you consume the class on the same place use a anonymous type as Mez wrote, althought it sounds like you want to hide the Property from external usage. (I don't like the dynamic approach, the dynamic keyword was made for interop/DOM not for transporting anonymous types.)
Option3:
If you want a List of this type to be returned without the Log property, you have to create a new class (Inheritance is a good way to realize this):
public class CompressedLogResponseBase
{
public string LoggerType { get; set; }
public int NumberOfRegisters { get; set; }
public int NewLogId { get; set; }
public DateTime LoggerAnnounceTime { get; set; }
}
public class CompressedLogResponse : CompressedLogResponseBase
{
public List<Log> Log{ get; set; }
}
Now you can return a list of base items (that do not have a Log property at all)
public List<CompressedLogResponseBase> ReturnWithoutLog(IEnumerable<CompressedLogResponse> items)
{
return ((IEnumerable<CompressedLogResponseBase>)items).ToList();
}
If a IEnumerable as return type is suficient it becomes really easy
public IEnumerable<CompressedLogResponseBase> ReturnWithoutLog(IEnumerable<CompressedLogResponse> items)
{
return items
}
whith "does not include the List Log property" i guess you mean that the property "public List Log" will be blanked but still there, so you can just null that property out, because if you create an object that doesn't contain the "public List Log" property, than it will not be a "CompressedLogResponse" but will be another type.
List<CompressedLogResponse> listOne = new List<CompressedLogResponse>();
//....
//fill the listOne
//....
List<CompressedLogResponse> listWithoutListLog = (from item in listOne
select new CompressedLogResponse(
LoggerType = item.LoggerType,
NumberOfRegisters = item.NumberOfRegisters ,
NewLogId = item.NewLogId ,
LoggerAnnounceTime = item.LoggerAnnounceTime ,
Log= null)).ToList();
You can return an anonymous list of your original list like the following;
public static List<dynamic> Test() {
List<CompressedLogResponse> list = new List<CompressedLogResponse>();
var result = list.Select(x => new
{
x.LoggerAnnounceTime,
x.LoggerType,
x.NewLogId,
x.NumberOfRegisters
});
return result.ToList<dynamic>();
}
Take a look at the .Select(), and also the dynamic keyword.
Then to call it,
var x = Test();
foreach(dynamic o in x)
{
int NumberOfRegisters;
//You have 2 ways... either by
NumberOfRegisters = o.NumberOfRegisters;
// or reflection
NumberOfRegisters = o.GetType().GetProperty("NumberOfRegisters").GetValue(o, null);
}
I have some data coming back from a web service, which I have mapped to the following classes:
public class Webinar {
public string Title { get; set; }
public string Description { get; set; }
...
public List<TimeZone> TimeZones { get; set; }
}
public class TimeZone {
public TimeSpan GmtOffset { get; set; }
public List<Session> Session { get; set; }
}
public class Session {
public int WebinarKey { get; set; }
public DateTime StartTime { get; set; }
public TimeSpan Duration { get; set; }
}
Hopefully it's fairly clear what is going on: any one webinar can have multiple time zones which in turn holds the individual sessions.
I have a list of webinars List<Webinar> webinars = ... which is populated with data. On the page I would like to present webinars grouped by time zone (easy) and then sorted by their start time.
My problem: the sessions are not necessarily ordered by StartTime when I receive the data, which I would like to do. I have the following code which does work, but recreating each object and mapping out all it's properties is a PITA, is there a nicer way to do what I want?
List<Webinar> webinarsWithOrderedSessions = new List<Webinar>();
foreach (Webinar webinar in mappedWebinars)
{
Webinar currentWebinar = new Webinar
{
Title = webinar.Title,
...
TimeZones = new List<TimeZone>()
};
foreach (Webinar.TimeZone timeZone in webinar.TimeZones)
{
Webinar.TimeZone currentTimeZone = new TimeZone
{
Location = timeZone.Location,
Sessions = new List<Session>()
};
currentTimeZone.Sessions = timeZone.Sessions.OrderBy(session => session.StartTime).ToList();
currentWebinar.TimeZones.Add(currentTimeZone);
}
webinarsWithOrderedSessions.Add(currentWebinar);
}
UPDATE
Building upon the suggestion by #Max, why might this bit of code not work? It doesn't seem to add the sessions at all. I don't necessarily need two properties, so I thought I'd just apply your suggestion directly to the main property.
public class TimeZone
{
private List<Session> _sessions;
public List<Session> Sessions
{
get { return _sessions.OrderBy(s => s.StartTime).ToList(); }
set { _sessions = value; }
}
}
You can try with this:
public class TimeZone
{
private List<Session> _ordered;
public TimeSpan GmtOffset { get; set; }
public List<Session> Session
{
get
{
return this._ordered;
}
set
{
if (value != null)
{
this._ordered = value.OrderBy(p => p.StartTime);
}
}
}
}
I has improved the answer using explicit set and get
Try this way:
var webinarsWithOrderedSessions = (from x in mappedWebinars
from y in x.TimeZones
from s in y.Session
orderby s.StartTime
select x).ToList();