Replacing/changing a blank or null string value in C# - c#

I've got something like this in my property/accessor method of a constructor for my program.
using System;
namespace BusinessTrips
{
public class Expense
{
private string paymentMethod;
public Expense()
{
}
public Expense(string pmtMthd)
{
paymentMethod = pmtMthd;
}
//This is where things get problematic
public string PaymentMethod
{
get
{
return paymentMethod;
}
set
{
if (string.IsNullOrWhiteSpace(" "))
paymentMethod = "~~unspecified~~";
else paymentMethod = value;
}
}
}
}
When a new attribute is entered, for PaymentMethod, which is null or a space, this clearly does not work. Any ideas?

do you perhaps just need to replace string.IsNullOrWhiteSpace(" ") with string.IsNullOrWhiteSpace(value) ?
From your posted code, you need to call:
this.PaymentMethod = pmtMthd;
instead of
paymentMethod = pmtMthd;
The capital p will use your property instead of the string directly. This is why it's a good idea to use this. when accessing class variables. In this case, it's the capital not the this. that makes the difference, but I'd get into the habit of using this.

Jean-Barnard Pellerin's answer is correct.
But here is the full code, which I tested in LinqPad to show that it works.
public class Foo {
private string _paymentMethod = "~~unspecified~~";
public string PaymentMethod
{
get
{
return _paymentMethod;
}
set
{
if (string.IsNullOrWhiteSpace(value))
_paymentMethod = "~~unspecified~~";
else _paymentMethod = value;
}
}
}
With a main of:
void Main()
{
var f = new Foo();
f.PaymentMethod = "";
Console.WriteLine(f.PaymentMethod);
f.PaymentMethod = " ";
Console.WriteLine(f.PaymentMethod);
f.PaymentMethod = "FooBar";
Console.WriteLine(f.PaymentMethod);
}
Output from console:
~~unspecified~~
~~unspecified~~
FooBar

Related

How to deserialize an array containing a list?

I would like to deserialize an array containing some things and 3 List.
The program works fine except for List. The lists are created but they contain nothing !
Can you help me ?
Here is how the xml file looks like :
<blind>
<folder>C:\Users\Michael\Desktop\BT 1 normal\Programme BT\</folder>
<nombre_titres>25</nombre_titres>
<numero></numero>
<theme></theme>
<heure_debut></heure_debut>
<mdp>a</mdp>
<lien></lien>
<playlist>
<extrait>
<artiste>Abba</artiste>
<titre>Take a chance on me</titre>
<PointAT>1.25</PointAT>
<PointA>0.5</PointA>
<PointT>0.5</PointT>
<JoueursAT>
<joueurAT>Ahkayaqua</joueurAT>
<joueurAT>Angelene</joueurAT>
</JoueursAT>
<JoueursA>
<joueurA></joueurA>
</JoueursA>
<JoueursT>
<joueurT></joueurT>
</JoueursT>
</extrait>
<extrait>
....
</extrait>
</playlist>
</blind>
My code to deserialize :
XElement xmle;
xmle = XElement.Load(_folder + "Blind.xml");
textBox1.Text = xmle.Element("numero").Value;
textBox4.Text = xmle.Element("theme").Value;
textBox3.Text = xmle.Element("heure_debut").Value;
textBox5.Text = xmle.Element("lien").Value;
textBox2.Text = xmle.Element("mdp").Value;
extraits = (from ex in xmle.Element("playlist").Elements("extrait")
select new Extrait
(ex.Element("artiste").Value,
ex.Element("titre").Value,
0,
0,
0,
(from jat in ex.Element("JoueursAT").Elements("JoueurAT")
select jat.Element("JoueurAT").Value).ToList(),
(from ja in ex.Element("JoueursA").Elements("JoueurA")
select ja.Element("JoueurA").Value).ToList(),
(from jt in ex.Element("JoueursT").Elements("JoueurT")
select jt.Element("JoueurT").Value).ToList())).ToArray();
And here is my class:
public class Extrait
{
private String _Artiste;
private String _Titre;
private double _PointA;
private double _PointT;
private double _PointAT;
private List<String> _JoueurA;
private List<String> _JoueurT;
private List<String> _JoueurAT;
public String Artiste
{
get { return _Artiste; }
set { _Artiste = value; }
}
public String Titre
{
get { return _Titre; }
set { _Titre = value; }
}
public Double PointA
{
get { return _PointA; }
set { _PointA = value; }
}
public Double PointT
{
get { return _PointT; }
set { _PointT = value; }
}
public Double PointAT
{
get { return _PointAT; }
set { _PointAT = value; }
}
public List<String> JoueurA
{
get { return _JoueurA; }
set { _JoueurA = value; }
}
public List<String> JoueurT
{
get { return _JoueurT; }
set { _JoueurT = value; }
}
public List<String> JoueurAT
{
get { return _JoueurAT; }
set { _JoueurAT = value; }
}
public Extrait(String Artiste, String Titre, Double PointA, Double PointT, Double PointAT, List<String> JoueurAT, List<String> JoueurA, List<String> JoueurT)
{
_Artiste = Artiste;
_Titre = Titre;
_PointA = PointA;
_PointT = PointT;
_PointAT = PointAT;
_JoueurAT = JoueurAT;
_JoueurA = JoueurA;
_JoueurT = JoueurT;
}
}
Well, I've tried many possibilities, but none worked !
If this is your actual xml, then look at the inner tags - they start with lower letter. Your xml have <joueurAT> while you selecting elements with name .Elements("JoueurAT") - node names are case-sensitive.
Your code should look like:
extraits = (from ex in xmle.Element("playlist").Elements("extrait")
select new Extrait
(ex.Element("artiste").Value,
ex.Element("titre").Value,
0,
0,
0,
(from jat in ex.Element("JoueursAT").Elements("joueurAT")
select jat.Value).ToList(),
(from ja in ex.Element("JoueursA").Elements("joueurA")
select ja.Value).ToList(),
(from jt in ex.Element("JoueursT").Elements("joueurT")
select jt.Value).ToList())).ToArray();
This should fix it. Basically the default behaviour is to use two-level nesting for lists (meaning it defaults to [XmlArray] plus [XmlArrayItem]; you only have one-level here, so you need to tell it.
[XmlElement]
public List<String> JoueurA
{
get { return _JoueurA; }
set { _JoueurA = value; }
}
[XmlElement]
public List<String> JoueurT
{
get { return _JoueurT; }
set { _JoueurT = value; }
}
[XmlElement]
public List<String> JoueurAT
{
get { return _JoueurAT; }
set { _JoueurAT = value; }
}
Btw; you might find it more convenient to use something like auto-properties here; an example for both regular properties and lists:
public double PointAT {get;set;}
[XmlElement]
public List<string> JoueurA {get;} = new List<string>();
This is a lot more convenient than messing with all the fields yourself.
You probably also want to make sure you have a public parameterless constructor; frankly I'd just remove the custom constructor (in which case: a public parameterless constructor is included for free), but otherwise - I'd just add:
public Extrait() {}
The change is needed in the blind class
[XmlRoot("blind")]
public class Blind
{
[XmlArray("playlist")]
[XmlArrayItem("extrait")]
public List<Extrait> extrait { get; set; }
}
public class Extrait
{
}
(from jat in ex.Element("JoueursAT").Elements("JoueurAT")
select jat.Element("JoueurAT").Value).ToList()
should become
(from jat in ex.Element("JoueursAT").Elements("joueurAT")
select jat.Value).ToList()
I'm not sure if C#'s XML library is case sensitive when it comes to token names, but when in doubt, it's better to play it safe.
You also tried to access an element "joueurAT" when making your select despite having actually looped over them already, so you can just access the Value property directly.
Also instead of using LINQ the way you do, you could try the extension methods, which tend to be more readable :
xmle.Element("playlist").Elements("extrait")
.Select(ex => new Extrait
{
Artiste = ex.Element("artiste").Value,
Titre = ex.Element("titre").Value,
PointA = 0,
PointT = 0,
PointAT = 0,
JoueurA = ex.Element("JoueursAT").Elements("joueurAT").Select(jat => jat.Value).ToList(),
JoueurT = ex.Element("JoueursA").Elements("joueurA").Select(ja => ja.Value).ToList(),
JoueurAT = ex.Element("JoueursT").Elements("joueurT").Select(jt => jt.Value).ToList()
});

Why do I not have access to these Properties?

I am having an issue passing properties from one class to another.
I'm getting an error saying that an object reference is required for all of the Game properties in the second class. They are highlighted at the bottom.
this is my first class (Game):
class Game
{
private string verb= "";
private string noun= "";
private string adjective= "";
private string panimal= "";
private string pnoun= "";
public string Verb
{
get {return verb; }
set {verb = value; }
}
public string Noun
{
get {return noun; }
set {noun = value; }
}
public string Adjective
{
get {return adjective;}
set {adjective = value; }
}
public string Panimal
{
get {return panimal; }
set {panimal = value; }
}
public string Pnoun
{
get {return pnoun; }
set {pnoun = value; }
}
public void InScreen()
{
Console.WriteLine("First, give me a past tense VERB: ");
Verb = Console.ReadLine();
Console.WriteLine("\nNow, give me a NOUN: ");
Noun = Console.ReadLine();
Console.WriteLine("\nNext, I will need an ADJECTIVE: ");
Adjective = Console.ReadLine();
Console.WriteLine("\nNow, I will need an ANIMAL(plural): ");
Panimal = Console.ReadLine();
Console.WriteLine("\nFinally, I neeed a plural NOUN: ");
Pnoun = Console.ReadLine();
}
My second class (InsertFunOOUI)
public void Poem()
{
Console.WriteLine("Humpty Dumpty " + **Game.Verb** + "on a " +
**Game.Noun**
);
Console.WriteLine("Humpty Dumpty had a " + **Game.Adjective** + "
fall"
);
}
...you get the picture.
Game is a Type. A class. You need to create an instance of it:
Game g = new Game();
and only then use:
g.Verb
etc.
You need to setup an instance of Game in order to use it, unless it you intended for it to be a static class.
Game game = new Game();
game.InScreen();
Something like that?
First create an instance of your game like #ispiro said. You need to do this once (in the main if possible). Then create an instance of your class poem. Use dependency injection and pass the properties of the game object in as parameters instead of the whole object if possible. I would even create a method inside your Poem class that handles the Console Output. Adapt this code to your liking:
public void main()
{
var game = new Game();
var poem = new Poem();
poem.Output(game.Verb, game.Adjective);
}
public class Poem()
{
public void Output(string verb, string adjective)
{
// your console writeline code
}
}

Passing a true value to a boolean

I am trying to learn C# and I am up to an example that uses a boolean. For the life of me I cant figure out why the program isnt noticing that I am trying to pass a value of true to the boolean. Here is the code in the Form.cs:
namespace WindowsFormsApplication7
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button2_Click(object sender, EventArgs e)
{
HappyBirthday birthdayMessage = new HappyBirthday();
string returnedMessage;
birthdayMessage.PresentCount = 5;
birthdayMessage.MyProperty = "Adam";
birthdayMessage.hasParty = true;
returnedMessage = birthdayMessage.MyProperty;
MessageBox.Show(returnedMessage);
}
}
}
Here is the Class that I created:
class HappyBirthday
{
//====================
// CLASS VARIABLES
//====================
private int numberOfPresents;
private string birthdayMessage;
private bool birthdayParty;
//===========================
// DEFAULT CONSTRUCTOR
//===========================
public HappyBirthday()
{
numberOfPresents = 0;
//birthdayParty = false;
}
//===========================
// METHOD
//===========================
private string getMessage(string givenName)
{
string theMessage;
theMessage = "Happy Birthday " + givenName + "\n";
theMessage += "Number of presents = ";
theMessage += numberOfPresents.ToString() + "\n";
if (birthdayParty == true)
{
theMessage += "Hope you enjoy the party!";
}
else
{
theMessage += "No party = sorry!";
}
return theMessage;
}
//================================
// READ AND WRITE PROPERTY
//================================
public string MyProperty
{
get { return birthdayMessage; }
set { birthdayMessage = getMessage(value); }
}
//================================
// WRITE-ONLY PROPERTY
//================================
public int PresentCount
{
set { numberOfPresents = value; }
}
public bool hasParty
{
set { birthdayParty = value; }
}
}
Now I set the initial value to false (even though if my understanding is correct that should be the default value), but when I try to set it = true, the program does not recognize it. Am I supposed to pass a boolean differently then I would a string or int?
You're setting MyProperty before you're setting hasParty. getMessage() is not being called every time MyProperty is polled.
The way MyProperty works is confusing, because the set and get deal with different values (you set the name, and then get the whole message, which is confusing). I'd replace it with a GivenName property and then make the GetMessage() (or expose it as a read-only property Message) public.
Also, you can make your code much simpler by using auto-properties (you can use private gets to keep the write-only behavior, though in the real world write-only properties are very rare, and you should probably just make them public like the sets). And since the default int value is 0, you don't need to specify your default constructor. Here's how the code looks now:
class HappyBirthday
{
public string Message
{
get
{
string theMessage;
theMessage = "Happy Birthday " + GivenName + "\n";
theMessage += "Number of presents = ";
theMessage += PresentCount.ToString() + "\n";
if (HasParty)
{
theMessage += "Hope you enjoy the party!";
}
else
{
theMessage += "No party = sorry!";
}
return theMessage;
}
}
public string GivenName { private get; set; }
public int PresentCount { private get; set; }
public bool HasParty { private get; set; }
}

Trying to get/set record

I am having problems getting and setting a value because I have introduced a third aspect into my code.
Previously I would do this to get/set in the record:
public virtual string MyString { get; set;}
and then in my part:
public string MyString
{
get { return Record.MyString; }
set { Record.MyString = value; }
}
and NHibernate would save my values in the DB (obviously my other code is not presented here for the sake of brevity).
Now I am trying to do a checkbox with a list. I have this for a checkbox:
public class MyPart : ContentPart<MyPartRecord>
{
public MyPart()
{
MyList = Enum.GetValues(typeof(MyEnum))
.Cast<MyEnum>().Select(x =>
{
return new SelectListItem { Text = x.ToString().ToUpper(),
Value = ((int)x).ToString() };
}).ToList();
}
public IList<SelectListItem> MyList { get; set; }
private string myCheckBox;
// Record class contains the following commented code:
// public virtual string MyCheckBox { get; set;}
// Trying to do this now here in MyPart class:
public string MyCheckBox
{
get
{
if (!string.IsNullOrEmpty(myCheckBox))
return myCheckBox;
// Tried the following commented code to get value:
// Record.MyCheckBox = myCheckBox;
return string.Join(",", MyList.Where(x => x.Selected)
.Select(x => x.Value).ToArray());
}
set
{
myCheckBox = value;
// Tried the following commented code to set value:
// Record.MyCheckBox = myCheckBox;
}
}
}
I just don't know how to assign the values in this case (getting/setting myCheckBox into MyCheckBox. It's being saved in the DB as null.
Thanks in advance for any help.
It seems to me you'd be hiding the base virtual implementation of MyCheckBox.
I think instead you'd rather override the base:
public override String MyCheckBox
{
get
{
if (!string.IsNullOrEmpty(myCheckBox))
return myCheckBox;
// Tried the following commented code to get value:
// Record.MyCheckBox = myCheckBox;
return string.Join(",", MyList.Where(x => x.Selected)
.Select(x => x.Value).ToArray());
}
set
{
myCheckBox = value;
// Tried the following commented code to set value:
// Record.MyCheckBox = myCheckBox;
}
}
Thereby becoming the variable instead of obfuscating it?
I wound up just getting rid of the part and sticking with only a record - this allowed me to do the get and set in a view model, which worked out better (and was less confusing).

Refactor C# automatic properties to fields and getter/setter property?

I have a bunch of business class with autoproperties :
public class A {
public int Id { get; set; }
public string Title { get; set;}
}
Because the application evolves, there is a new requirement to enable tracking the changes of the properties, in order to send to the backing store only changed data.
In order to reach this goal, I have to convert ALL properties to field + property like this :
public class A {
private int m_Id;
public int Id {
get { return m_Id; }
set {
if(m_Id != value){
SetChanged("Id");
m_Id = value;
}
}
}
private string m_Title;
public string Title
{
get { return m_Title; }
set {
if(m_Title != value){
SetChanged("Title");
m_Title = value;
}
}
}
protecte void SetChanged(string propertyName) {
// Not important here
}
}
Is there a way to quickly refactor my code to avoid having to manually change the properties ?
There's no way in the IDE to do this, but if you need to replace all X properties, I would write a short console application to do it.
The process would be:
Iterate over all files in directory matching *.cs
Foreach file, regex find and replace old property for new property syntax
Using regex to match is very powerful. Regex can be used in VS2010 to do a find/replace operation. If you try finding this (with regex enabled)
{(public|private|internal|protected)}:b{[a-zA-Z0-9]+}
:b{[a-zA-Z0-9]+}:b\{ get; set; \}
It will match properties like this
public Type Foo { get; set; }
In your console application find all lines of code that match the above, then start splitting them up into Modifier, Type, Property Name and finally replacing the whole block with something like this
// PS: this is pseudocode ;-) or could be your new property template
private [Type] m_[PropertyName].ToPascaleCase
public [Type] PropertyName
{
get { return m_[PropertyName].ToPascaleCase; }
set
{
if(m_[PropertyName].ToPascaleCase != value){
SetChanged([PropertyName]);
m_[PropertyName].ToPascaleCase = value;
}
}
}
Finally I would advocate taking a backup of your code or running this test offline and testing before checking in!!
You can always just create a generic method that will do the assignment and call SetChange
void SetChangeIfNeeded<T>(ref T field, T value, string propertyName)
{
if (!EqualityComparer<T>.Default.Equals(field, value))
{
field = value;
SetChanged(property);
}
}
You would still need to have a private back field. Your class would look something like:
public class A {
private int m_id
public int Id
{
get { return m_id };
set { SetChangeIfNeeded<int>(ref m_id, value, "Id"); }
}
}
ReSharper can do this, but wouldn't modify setter.
public string Title {
get { return m_title; }
set { m_title = value; }
}
There is probably no direct way of doing this with refraction. If this was my problem. I would make code to generate this:
public string MakePropertyBigger(string varName, string propName, string dataType)
{
string output = "";
output += string.Format("private {0} {1};", dataType, varName) + Environment.NewLine;
output += string.Format("public {0} {1}", dataType, propName) + Environment.NewLine;
output += "{" + Environment.NewLine;
output += string.Format("get { return {0}; }", varName) + Environment.NewLine;
output += string.Format("set { if({0} != value){ SetChanged(\"{1}\");", varName, propName) + Environment.NewLine;
output += string.Format("{0} = value; }", varName) + Environment.NewLine;
output + "}" + Environment.NewLine + "}";
Now just plug this in and chug it out.

Categories