I want to validate Json code after I deserialize it.
For example if I have ...
using Newtonsoft.Json;
...
public Car
{
public int Year{ get; set; }
public String Make{ get; set; }
}
...
JsonConvert.DeserializeObject<Car>(json)
I want to validate that the year is < 2017 && >=1900, (for example).
Or maybe make sure that the Make is a non empty string, (or it is an acceptable value).
I know I could add a Validate() type function after I deserialize, but I am curious if there was a way of doing it at the same time as the JsonConvert.DeserializeObject<Car>(json)
Probably the right tool for the job is a serialization callback
Just create a Validate method and slap on it an [OnDeserialized] attribute:
public Car
{
public int Year{ get; set; }
public String Make{ get; set; }
[OnDeserialized]
internal void OnDeserializedMethod(StreamingContext context)
{
if (Year > 2017 || Year < 1900)
throw new InvalidOperationException("...or something else");
}
}
Plug it in with the Setters.
public class Car
{
private int _year;
public int Year
{
get { return _year; }
set
{
if (_year > 2017 || _year < 1900)
throw new Exception("Illegal year");
_year = value;
}
}
}
For entire object validation, just validate anytime a value is set.
public class Car
{
private int _year;
private string _make;
public string Make
{
get { return _make; }
set
{
_make = value;
ValidateIfAllValuesSet();
}
}
public int Year
{
get { return _year; }
set
{
_year = value;
ValidateIfAllValuesSet();
}
}
private void ValidateIfAllValuesSet()
{
if (_year == default(int) || _make == default(string))
return;
if (_year > 2017 || _year < 1900)
throw new Exception("Illegal year");
}
}
Related
I was expected that constructor can go into the setter condition, I have done the following attempts.
static void Main(string[] args)
{
Iitem car = new Car(7000);
Console.WriteLine($"cost={car.cost}");//expect output "too expensive",but actually show 7000
car.cost = 7000;
Console.ReadLine();
}
public interface Iitem
{
int cost { get; set; }
string status {get;set; }
}
class Car:Iitem
{
private int mycost;
public int cost
{
get { return mycost; }
set
{
if (value > 5000)
{
mycost = 0;
Console.WriteLine("too expensive");
}
else
{
mycost = value;
}
}
}
public string status { get; set; }
public Car(int cost)
{
this.mycost = cost;
}
}
If I discard car.cost=7000 from Main() function, then I can't get the output of too expensive.
you are not getting the desired result because you are setting the value directly into the variable "mycost" in the constructor. Replace it with this.cost = cost;
I'm trying to pass some tests in the Exercism C# exercise 'weighing machine' which uses properties. I have these properties:
using System;
enum Units
{
Pounds,
Kilograms
}
class WeighingMachine
{
private decimal inputWeight;
public decimal InputWeight
{
get { return inputWeight; }
set { if (value >= 0)
inputWeight = value;
else throw new ArgumentOutOfRangeException();
}
}
private decimal displayWeight;
public decimal DisplayWeight
{
get
{ return displayWeight; }
set
{
displayWeight = InputWeight - TareAdjustment;
if (displayWeight <= 0)
throw new ArgumentOutOfRangeException();
}
}
private decimal _pounds;
public USWeight USDisplayWeight
{
get { return _pounds; }
set { _pounds = new USWeight(InputWeight).Pounds; }
}
public decimal TareAdjustment { private get; set; }
public int Units
{ get; set; }
}
struct USWeight
{
public USWeight(decimal weightInPounds)
{
Pounds = (int)weightInPounds;
Ounces = (weightInPounds - Pounds)*16;
}
public int Pounds { get; set; }
public decimal Ounces { get; set; }
}
My stumbling block is the tests:
[Fact]
public void Get_us_display_weight_pounds()
{
var wm = new WeighingMachine();
wm.InputWeight = 60m;
Assert.Equal(132, wm.USDisplayWeight.Pounds);
}
I can't get my head around how the test is asking for wm.USDisplayWeight.Pounds - how is the .Pounds accessed on the end? it's like there is a property set within the USDisplayWeight property, but that's not possible is it? I can't make the compiler stop complaining about the .Pounds - I get ''decimal' does not contain a definition for 'Pounds' and no accessible extension method 'Pounds' accepting a first argument of type 'decimal' could be found.
I'm sure it's a simple thing that I'm overlooking here, but I would appreciate any help at all.
As shown in the first class displayed, I need to cast Activité to Réunion (Réunion extends Activité) but the compiler tells me that I can't. Why? I'll put a scheme so you can better understand my classes structure and also all my other classes. Thank you.
class Employé<T>
{
private string nom;
private Local bureau;
private LinkedList<Activité<T>> activités;
public Employé(string nom, Local bureau)
{
this.nom = nom;
this.bureau = bureau;
}
public void AjouteActivité(params Activité<T>[] activités)
{
foreach(Activité<T> activité in activités)
{
if (activité as Réunion != null)
// here's the problem !!! ((Réunion)activité).EmployéConvoqués = activité;
}
}
}
Here's the scheme of my classes structure:
And here are the other classes:
abstract class Activité<T>
{
private string label;
private DateTime début, fin;
private T lieu;
private readonly int id;
private static int CPT = 0;
public Activité(string label, DateTime début, DateTime fin, T lieu)
{
this.label = label;
this.début = début;
this.fin = fin;
this.lieu = lieu;
this.id = ++CPT;
}
public override string ToString()
{
return $"{id} : {label}(de {début} à {fin}) - {DescriptionLieu()}";
}
public double Duree()
{
return fin.Subtract(début).TotalMinutes;
}
public int Id
{
//tester get; seulement
get
{
return id;
}
}
public T Lieu
{
get
{
return lieu;
}
}
public abstract string DescriptionLieu();
}
class ActivitéExtérieure : Activité<string>
{
public ActivitéExtérieure(string label, DateTime début, DateTime fin, string lieu) : base(label,début,fin,lieu) { }
public override string DescriptionLieu()
{
return Lieu;
}
}
class ActivitéInterne : Activité<Local>
{
public ActivitéInterne(string label, DateTime début, DateTime fin, Local lieu) : base(label,début,fin,lieu)
{
lieu.AjouteActivité(this);
}
public override string DescriptionLieu()
{
return $"local :: {Lieu.NumComplet}";
}
}
class Employé<T>
{
private string nom;
private Local bureau;
private LinkedList<Activité<T>> activités;
public Employé(string nom, Local bureau)
{
this.nom = nom;
this.bureau = bureau;
}
public void AjouteActivité(params Activité<T>[] activités)
{
foreach(Activité<T> activité in activités)
{
if (activité as Réunion != null)
((Réunion)activité).EmployéConvoqués = activité;
}
}
}
class Local
{
private int etage;
private int numero;
private bool possedeWifi;
private Dictionary<int, ActivitéInterne> historiquesActivités;
public int Numero
{
get
{
return numero;
}
set
{
if (value < 0 || value > 99)
throw new IndexOutOfRangeException();
else
numero = value;
}
}
public int NumComplet
{
get
{
return etage * 100 + numero;
}
}
public bool PossedeWifi
{
get
{
return possedeWifi;
}
}
public Local(int etage, bool possedeWifi, int numero)
{
this.etage = etage;
this.possedeWifi = possedeWifi;
Numero = numero;
}
public Local(int etage, int numero) : this(etage, true, numero) { }
public Local(int local, bool possedeWifi) : this(local / 100, possedeWifi, local % 100) { }
public void AjouteActivité(ActivitéInterne a)
{
historiquesActivités.Add(a.Id, a);
}
}
class Réunion : ActivitéInterne
{
private HashSet<Employé<Local>> employésConvoqués;
public Réunion(string label, DateTime début, DateTime fin, Local lieu) : base(label, début, fin, lieu) { }
public Employé<Local> EmployéConvoqués
{
set
{
employésConvoqués.Add(value);
}
}
}
The error message says that "cast is redundant". This is because you have already tested for "activité as Réunion != null". The compiler figures out that in the 'if' clause this condition is already true, therefore the cast is not meaningful. On the other hand you cannot access activité.EmployéConvoqués because the static type of activité is not Réunion.
All you have to do is introduce a new variable when testing the type. Like this:
if (activité is Réunion réunion) {
réunion.EmployéConvoqués = activité;
}
However if you try this you will see that the assignment cannot be done because you are trying to assign an activity to an Employé<Local>. These are not compatible types. Perhaps you meant something like
foreach (Activité<T> activité in activités) {
if (activité is Réunion réunion && this is Employé<Local> employéLocal) {
réunion.EmployéConvoqués = employéLocal;
}
}
Comment: in the definition of Réunion you are adding to HashSet<Employé<Local>> employésConvoqués when setting the property Employé<Local> EmployéConvoqués. From a style point of view this is strange because people generally expect a property of type Employé<Local> will represent a single Employé<Local> rather than a collection of Employé<Local>. I would suggest that you remove the setter and instead define
public void Ajoute( Employé<Local> employéConvoqué) {
this.employésConvoqués.Add(employéConvoqué);
}
Is there a standard naming convention for the properties/methods of a node/relationship class when working with Neo4jClient?
I'm following this link Neo4jClient - Retrieving relationship from Cypher query to create my relationship class
However, there are certain properties of my relationship which i can't get any value despite the relationship having it. While debugging my code, i realized certain properties was not retrieved from the relationship when creating the relationship object.
this is my relationship class
public class Creates
{
private string _raw;
private int _sourcePort;
private string _image;
private int _DestinationPort;
private int _eventcode;
private string _name;
private string _src_ip;
private int _src_port;
private string _dvc;
private int _signature_ID;
private string _dest_ip;
private string _computer;
private string _sourceType;
private int _recordID;
private int _processID;
private DateTime _time;
private int _dest_port;
public string Raw { get { return _raw; } set { _raw = value; } }
public int SourcePort { get { return _sourcePort; } set { _sourcePort = value; } }
public string Image { get { return _image; } set { _image = value; } }
public int DestinationPort { get { return _DestinationPort; } set { _DestinationPort = value; } }
public int Eventcode { get { return _eventcode; } set { _eventcode = value; } }
public string Name { get { return _name; } set { _name = value; } }
public string Src_ip { get { return _src_ip; } set { _src_ip = value; } }
public int Src_port { get { return _src_port; } set { _src_port = value; } }
public string DVC { get { return _dvc; } set { _dvc = value; } }
public int Signature_ID { get { return _signature_ID; } set { _signature_ID = value; } }
public string Dest_ip { get { return _dest_ip; } set { _dest_ip = value; } }
public string Computer { get { return _computer; } set { _computer = value; } }
public string SourceType { get { return _sourceType; } set { _sourceType = value; } }
public int RecordID { get { return _recordID; } set { _recordID = value; } }
public int ProcessID { get { return _processID; } set { _processID = value; } }
public DateTime Indextime { get { return _time; } set { _time = value; } }
public int Dest_port { get { return _dest_port; } set { _dest_port = value; } }
}
This is another class
public class ProcessConnectedIP
{
public Neo4jClient.RelationshipInstance<Pivot> bindto { get; set; }
public Neo4jClient.Node<LogEvent> bindip { get; set; }
public Neo4jClient.RelationshipInstance<Pivot> connectto { get; set; }
public Neo4jClient.Node<LogEvent> connectip { get; set; }
}
This is my neo4jclient query to get the relationship object
public IEnumerable<ProcessConnectedIP> GetConnectedIPs(string nodeName)
{
try
{
var result =
this.client.Cypher.Match("(sourceNode:Process{name:{nameParam}})-[b:Bind_IP]->(bind:IP_Address)-[c:Connect_IP]->(connect:IP_Address)")
.WithParam("nameParam", nodeName)
.Where("b.dest_ip = c.dest_ip")
.AndWhere("c.Image=~{imageParam}")
.WithParam("imageParam", $".*" + nodeName + ".*")
.Return((b, bind, c, connect) => new ProcessConnectedIP
{
bindto = b.As<RelationshipInstance<Creates>>(),
bindip = bind.As<Node<LogEvent>>(),
connectto = c.As<RelationshipInstance<Creates>>(),
connectip = connect.As<Node<LogEvent>>()
})
.Results;
return result;
}catch(Exception ex)
{
Console.WriteLine("GetConnectedIPs: Error Msg: " + ex.Message);
return null;
}
}
This is the method to read the results
public void MyMethod(string name)
{
IEnumerable<ProcessConnectedIP> result = clientDAL.GetConnectedIPs(name);
if(result != null)
{
var results = result.ToList();
Console.WriteLine(results.Count());
foreach (ProcessConnectedIP item in results)
{
Console.WriteLine(item.Data.Src_ip);
Console.WriteLine(item.bindto.StartNodeReference.Id);
Console.WriteLine(item.bindto.EndNodeReference.Id);
Console.WriteLine(item.connectto.StartNodeReference.Id);
Console.WriteLine(item.connectto.EndNodeReference.Id);
Node<LogEvent> ans = item.bindip;
LogEvent log = ans.Data;
Console.WriteLine(log.Name);
Node<LogEvent> ans1 = item.connectip;
LogEvent log1 = ans1.Data;
Console.WriteLine(log1.Name);
}
}
}
Somehow, i'm only able to populate the relationship object with src_ip/src_port/dest_ip/dest_port values. the rest are empty.
Is there any possible reason why? I've played with upper/lower cases on the properties names but it does not seem to work.
This is the section of the graph im working with
This is the relationship properties sample:
_raw: Some XML dataSourcePort: 49767Image: C:\Windows\explorer.exeDestinationPort: 443EventCode: 3Name: Bind
IPsrc_ip: 172.10.10.104dvc: COMPUTER-NAMEsrc_port:
49767signature_id: 3dest_ip: 172.10.10.11Computer:
COMPUTRE-NAME_sourcetype:
XmlWinEventLog:Microsoft-Windows-Sysmon/OperationalRecordID:
13405621ProcessId: 7184_time: 2017-08-28T15:15:39+08:00dest_port: 443
I'm not entirely sure how your Creates class is ever populated, in particular those fields - as your Src_port property doesn't match the src_port in the sample you provided (case wise).
I think it's probably best to go back to a super simple version. Neo4jClient will map your properties to the properties in the Relationship as long as they have the same name (and it is case-sensitive).
So start with a new Creates class (and use auto properties - it'll make your life a lot easier!)
public class Creates
{
public string Computer { get; set; }
}
Run your query with that and see if you get a result, then keep on adding properties that match the name and type you expect to get back (int, string etc)
It seems that i have to give neo4j node/relationship property names in lowercase and without special characters at the start of the property name, in order for the above codes to work.
The graph was not created by me at the start thus i had to work on it with what was given. I had to get the developer who created the graph to create the nodes with lowercases in order for the above to work.
my question is, if it's possible, to do something like this:
public Class Test
{
public int Number { get; set; }
private string text;
public string Text
{
if (Number > 5)
{
set {text = value;}
get {return text;}
}
}
}
No, but you could do something like:
public class Test {
public int Number { get; set; }
private string _Text;
public string Text {
get {
if(Number > 5) {
return _Text;
} else {
//DEFAULT value here.
return null;
}
}
set {
if(Number > 5) {
_Text = value;
} else {
//DEFAULT Value.
_Text = null;
}
}
}
}
I would also check out Preprocessor Directives if you are using Visual Studio. These might be more helpful depending on how you are trying to use the code.
Preprocess Directives:
https://msdn.microsoft.com/en-us/library/3sxhs2ty.aspx