XML Deserialization and string format - c#

I have an XML like this:
"<ArrayOfClsLog xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">
<ClsLog>
<Subject>sth</Subject>
<Value>123456</Value>
<Comment>val</Comment>
</ClsLog>
</ArrayOfClsLog>"
and with this code I desterilize it:
var tmpSerializer = new XmlSerializer(typeof(ObservableCollection<ClsLog>));
tmpResult = tmpSerializer.Deserialize(tmpReader) as ObservableCollection<ClsLog>;
here is my ClsLog:
public class ClsLog
{
public string Subject { get; set; }
public string Value {get; set;}
public string Comment { get; set; }
}
Everything is fine except:
Big Problem
I want the content of value which can be a number like 123456 converts into 123,456
So I've changed Clslog to :
public class ClsLog
{
public string Subject { get; set; }
public string Value {
get
{
return decimal.Parse(Value.ToString()).ToString("N2", System.Globalization.CultureInfo.InvariantCulture);
}
set
{ }
}
public string Comment { get; set; }
}
But nothing changed, also I've tried to change tmpResult with LINQ:
tmpResult=tmpResult.ToList().ForEach(i => i.Value =
decimal.Parse( i.Value.ToString()).ToString("N2", System.Globalization.CultureInfo.InvariantCulture));
So bad exception happened and turned out I can't change it manually.
Question
How I can fix it? (make value from 123456 to 123.456)

You are declaring this property wrong.
public string Value //why a string why not a decimal?
{
get
{
// you have an infinite recursion here
return decimal.Parse(Value.ToString()).ToString("N2", System.Globalization.CultureInfo.InvariantCulture);
}
set { } // the setter is empty anyway so youcan't set it.
}
Instead try this
private decimal _value; // internal field
public decimal Value
{
get
{
return _value; // return internal field
}
set
{
_value = value / 1000; // set the internal field to the value / 1000
}
}

Related

Is it possible to override GetValue() method for complex types?

I have a Job class as below:
public class Job
{
public string JobTitle { get; set; }
public SalaryRange SalaryRange { get; set; }
}
public class SalaryRange
{
public decimal MinSalary { get; set; }
public decimal MaxSalary { get; set; }
}
Now I want to calculate the checksum of job object. The purpose of this checksum is to indicate if any property of job has been modified... so I want to build a string which contains all of its property values and get the checksum of this string:
[TestMethod]
public void Calculate_job_checksum()
{
var salary = new SalaryRange()
{
MinSalary = 15,
MaxSalary = 20
};
vat job = new Job()
{
JobTitle= "Civil Engineer",
SalaryRange = salary
};
string stringifiedValues = "";
PropertyInfo[] properties = job.GetType().GetProperties();
foreach (PropertyInfo p in properties)
{
if (p.CanRead))
{
// combine all values
var val = p.GetValue(job);
stringifiedValues += val.ToString();
}
}
// get the checksum
jobChecksum = stringifiedValues.GetChecksum();
}
The problem is GetValue() does not get the value of the complex type (i.e. SalaryRange) correctly, it returns the namespace of the class, i.e. the value of stringifiedValues is:
"Civil EngineerMySolutionName.ProjectName.FolderName"
Is it possible to override or change the behavior of GetValue() to return stringified values of nested properties?
It is fetching the value just fine; the problem is that the value is a SalaryRange instance, and the default object.ToString() implementation is to write the type name. You could just override that:
public class SalaryRange
{
public decimal MinSalary { get; set; }
public decimal MaxSalary { get; set; }
public override string ToString() => $"{MinSalary}-{MaxSalary}"; // for example
}

Using setter in ViewModel using another property

I have the following ViewModel in my app and there is two BirthDate property (with / without time). When using set { } without body I encounter "Not using the value means that the accessor ignores the caller's intent which could cause unexpected results at runtime.". Then I added a private property and update set as set { birthDateWithTime = value; }. However, this time birthDateWithTime private property not sees to be used. Is there any mistake regarding to implementation below? I want to use both property separately and do not want to convert in JavaScript or code.
public class DemoViewModel
{
public int Id { get; set; }
public DateTime BirthDate { get; set; }
private string birthDateWithTime;
public string BirthDateWithTime {
get { return BirthDate.ToString("dd/MM/yyyy - HH:mm"); }
set { birthDateWithTime = value; }
}
}
#Gabriel Llorico answer is correct. or maybe you can try another one.
private DateTime _birthDate;
public DateTime BirthDate{
get{
return _birthDate;
}
set{
this._birthDate = value;
this.BirthDateWithTime = this._birthDate.ToString("dd/MM/yyyy - HH:mm");
}
}
public string BirthDateWithTime{get;set;}
try this if it is solely dependent on BirthDate
public string BirthDateWithTime
{
get
{
return BirthDate.ToString("dd/MM/yyyy - HH:mm");
}
}
Or just use a body-property style.
public string BirthDateWithTime => BirthDate.ToString("dd/MM/yyyy - HH:mm");
If you need to set BirthDateWithTime, just set in the BirthDate property, so both are updated.

C# trim within the get; set;

I am total MVC newbie coming from 10 years of webforms. Here is the code I have inherited:
namespace sample.Models
{
public class Pages
{
public int PageID { get; set; }
public string FolderName { get; set; }
}
}
How can I apply a trim function to the "set" portion of this code? Right now it is allowing spaces at the end of foldername and I need to prevent that.
Okay I have incorporated the suggestions however the spaces are still getting saved.
Here are the UI/ vs Database. The UI is trimming properly but the full value with spaces is stored in the table:
You need a backing field:
public class Pages
{
public int PageID { get; set; }
private string _folderName;
public string FolderName
{
get { return _folderName; }
set { _folderName = value.Trim(); }
}
}
In the setter method we use the Trim string's method, which
Removes all leading and trailing white-space characters from the current String object.
For further info regarding this method, please have a look here.
What about this solution:
public class Pages
{
private string _folderName;
public int PageID { get; set; }
public string FolderName
{
get { return _folderName; }
set { _folderName = value?.Trim() ?? string.Empty; }
}
}
You may consider writing a custom extension method to call Trim only if the value of your string is not null:
public static class CustomExtensions
{
public static string TrimIfNotNull(this string value)
{
if (value != null)
{
value = value.Trim();
}
return value;
}
}
And then in your Pages class, something like
private string _folderName;
public string FolderName
{
get { return _folderName.TrimIfNotNull(); }
set { _folderName = value.TrimIfNotNull(); }
}
If you're using C#6, as mentioned by Jacob Krall, you can use the null conditional operator directly and not worry about the extension method:
public string FolderName
{
get { return _folderName; }
set { _folderName = value?.Trim(); }
}
The shorthand syntax for properties is only for when you want to provide a thin layer of abstraction on top of a field. If you want to manipulate the field within the getter or setter, you need to specify the backing field on your own.
namespace sample.Models
{
public class Pages
{
public int PageID { get; set; }
private string folderName;
public string FolderName
{
get { return folderName; }
set { folderName = value.Trim(); }
}
}
}
public class Pages
{
public int PageId { get; set; }
// you need a backing field then you can customize the set and get code
private string folderName;
public string FolderName
{
get { return this.folderName; }
// if the fileName can be set to null you'll want to use ?. or you'll get
// a null reference exception
set { this.folderName = value?.Trim(); }
}
}
See the code below.
//You can filter the entry before saving it into the database.
//About the null issue. You can use this.
if(String.IsNullOrEmpty(txtusername.Text))
{
throw new Exception("Cannot be blank!");
}
//You can filter the entry before saving it into the database
txtpageid.Text = book.PageID.Trim();
txtfoldername.Text = book.FolderName.Trim();

Update automatically property

I have one class :
public class Car
{
public string Color { get; set; }
public string Speed { get; set; }
public string Property3 { get; set; }
}
I want to set automatically the value of Property3 when property Color or Speed are updated
I want to set the value of Property3 with the concatenation of value Color and Speed separated with hyphen
What is the best way to do this ?
You can specify that in the getter of Property3 - something like this:
public string Property3
{
get { return $"{this.Color}-{this.Speed}"; }
}
I assume that you want Property3 to be read only so I omitted the setter in the sample above
you can set that getter property like this
public string Property3 {
get { return Color + "-" + Speed; }
}
You have two ways:
Update the dependent property within setters of speed and color:
private string _Color;
public string Color
{
get
{
return this._Color;
}
set
{
this._Color = value;
this.Property3 = $"{this.Color}-{this.Speed}";
}
}
private string _Speed;
public string Speed
{
get
{
return this._Speed;
}
set
{
this._Speed = value;
this.Property3 = $"{this.Color}-{this.Speed}";
}
}
public string Property3 { get; set; }
Concatenation within get of the dependent property:
public string Property3
{
get
{
return $"{this.Color}-{this.Speed}";
}
}
Conceptual difference is quite obvious: Do you want to be able to overwrite Property3 or should it be read only.

Storing/retrieving a JSON string in the database making it easy to work with in code

I have a c# object 'Product' with a property called: Offset
In the database the field is of type nvarchar(50)
I will be storing a JSON value in it such as the following: { "y": 0, "m": 0, "d": 0 }
I would like to know a good way of working with a property like this in my code. Here is how I currently am doing it:
public class Product
{
public int Id {get; set;}
public string Description {get; set;}
public decimal Price {get; set;}
public int OffsetYears { get; set; }
public int OffsetMonths { get; set; }
public int OffsetDays { get; set; }
public string Offset
{
get
{
Offset offset = new Offset()
{
Y = OffsetYears,
M = OffsetMonths,
D = OffsetDays
};
return JsonConvert.SerializeObject(offset);
}
set
{
OffsetObj offset = JsonConvert.DeserializeObject<Offset>(value);
OffsetYears = offset.Y;
OffsetMonths = offset.M;
OffsetDays = offset.D;
}
}
private class OffsetObj
{
public int Y { get; set; }
public int M { get; set; }
public int D { get; set; }
}
}
So then when I accept values from the User in the UI I would set the OffsetYears, OffsetMonths, and OffsetDays properties.. So in my repository I can just save Offset.
And when retrieving values from the database I will simply work with OffsetYears, OffsetMonths, and OffsetDays properties in my code.
Is there a better way to handle this sort of thing? I just feel like I am not utilizing all of my c# resources. Like what if another developer accidentally sets Offset through the code assuming any format of string can go in it.
Or am I better off just creating 3 separate integer fields in the database and avoiding all of this...
I would hold the values in a field of your private type. Consider this approach:
public class Product
{
private OffsetObj _offset = new OffsetObj();
public int Id { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public int OffsetYears
{
get { return _offset.Y; }
set { _offset.Y = value; }
}
public int OffsetMonths
{
get { return _offset.M; }
set { _offset.M = value; }
}
public int OffsetDays
{
get { return _offset.D; }
set { _offset.D = value; }
}
public string Offset
{
get
{
return JsonConvert.SerializeObject(_offset);
}
set
{
_offset = JsonConvert.DeserializeObject<OffsetObj>(value);
}
}
private class OffsetObj
{
public int Y { get; set; }
public int M { get; set; }
public int D { get; set; }
}
}
This way, the field offset will hold the values for the offset.
Like what if another developer accidentally sets Offset through the code assuming any format of string can go in it.
JsonConvert will throw a JsonReaderException if trying to set the Offset property to a string that does not match JSON-format. In my opinion this is expected. To clarify further, you could name your property to OffsetJson.
However, I fail to see the benefit in this simple case to store your information as JSON. If you are using a relational database, you may as well just store your values in separate columns.

Categories

Resources