Stackoverflow Exception on get function for a property - c#

I have the following simple class to manage my SQL database operations
public class DatabaseManager
{
private string CommandString
{
set { CommandString = GetCommandString(commandtype); }
get { return CommandString; }
}
public string commandtype
{
set;
get;
}
public DatabaseManager(string commandtype)
{
commandtype = this.commandtype;
CommandString = GetCommandString(commandtype);
}
public DatabaseManager()
{
}
public static SqlConnection CreateConnection()
{
return new SqlConnection(Properties.Settings.Default.connectionString);
}
//returns a datatable if the command requires a dataadapter
public DataTable ExecuteSelect()
{
var x = new DataTable();
using (var da = new SqlDataAdapter(CommandString, DatabaseManager.CreateConnection()))
{
da.Fill(x);
}
return x;
}
private string GetCommandString(string commandtype)
{
switch (commandtype)
{
// select commands
case ("SELECTMARGINS"): CommandString = "select * from margins"; break;
case ("SELECTRANKS"): CommandString = "select * from ranks"; break;
/...and other commands
return CommandString;
}
}
i am getting a Stackoverflow exception on get { return CommandString; }

The get function is your problem
get { return CommandString; }
This is the morale equivalent of the following
public string GetCommandString() {
return GetCommandString();
}
This will just create infinite recursion and eventually a StackOverflowException will be thrown. You need to change the get and set to operate on a backing field which holds the actual value and use that instead
private string _commandString;
public string CommandString {
get { return _commandString; }
set { _commandString = GetCommandString(commandtype); }
}

You can't have a property return itself (it creates an infinite loop).
private string _CommandString;
public string CommandString
{
set { _CommandString = GetCommandString(commandtype); }
get { return _CommandString; }
}

You can't have a Get function return itself, it will just cause it to infinitely attempt to retrieve itself until the stack overflows.
Create a private variable to get and set to:
private string _CommandString;
private string CommandString
{
//Also you probably want to change commandtype to value, since you will be
//discarding whatever you attempt to set the variable as
set { _CommandString = GetCommandString(commandtype); }
get { return _CommandString; }
}

You cannot set or even get CommandString, you have to create a private variable in this case.
private string _commandString;
public string CommandString
{
set { _commandString = GetCommandString(commandtype); }
get { return _commandString; }
}
What is happening in your current code is that you are doing something like this:
CommandString = "x";
which calls
CommandString = GetCommandString(type);
which calls
CommandString = GetCommandString(type);
etc....so it keeps looping until it overflow. The private variable keeps you from setting the same property over and over again
Also, it looks like you are never actually using the value passed into the set function, which seems like a bug

Related

how can i convert a null value from sql to datetime or string in C#?

I am trying to get some datetime values that are null in SQL to my C# application but i get some errors. One of the errors is:
'Unable to cast object of type 'System.DBNull' to type 'System.String'
Please, can someone tell me how to set a null DateTime value from SQL to my c# application?
I have already tried casting my C# variables to datetime value and string but both dont work. I've searched in stackoverflow but didn't found a solution for me.
I've also tried another solution but then i retrieved the date: '01/01/0001' as value instead of 'null'
public static List<Kamer> GetOpenstaandeBoekingen()
{
var result = new List<Kamer>();
using (var conn = new SqlConnection(ConnectionString))
{
conn.Open();
const string query = "select b.boekingid, k.naam, bk.incheckdatum, bk.uitcheckdatum, b.hotelid, b.aantal_gasten, bk.kamerid from boeking b join klant k on k.klantid = b.boekingid join boekingkamer bk on b.boekingid = bk.boekingid where bk.incheckdatum is null and bk.uitcheckdatum is null";
SqlCommand selectKamers = new SqlCommand(query, conn);
SqlDataReader reader = selectKamers.ExecuteReader();
while (reader.Read())
{
Kamer kamer = new Kamer((int)reader["boekingid"], (string)reader["naam"], (string)reader["incheckdatum"], (string)reader["uitcheckdatum"], (int)reader["hotelid"], (int)reader["aantal_gasten"], (int)reader["kamerid"]);
result.Add(kamer);
}
reader.Close();
}
return result;
}
And here is my class with the constructor:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FontysHotel
{
public class Kamer
{
// instantie variabelen
private int id;
private string naam;
private DateTime incheck_datum;
private DateTime uitcheck_datum;
private int hotel;
private int aantal_personen;
private int kamernr;
// properties
public int Id
{
get
{
return id;
}
set
{
id = value;
}
}
public string Naam
{
get
{
return naam;
}
set
{
naam = value;
}
}
public string Incheck_datum
{
get
{
return incheck_datum.ToShortDateString();
}
set
{
incheck_datum = Convert.ToDateTime(value);
}
}
public string Uitcheck_datum
{
get
{
return uitcheck_datum.ToShortDateString();
}
set
{
uitcheck_datum = Convert.ToDateTime(value);
}
}
public int Hotel
{
get
{
return hotel;
}
set
{
hotel = value;
}
}
public int Aantal_personen
{
get
{
return aantal_personen;
}
set
{
aantal_personen = value;
}
}
public int Kamernr
{
get
{
return kamernr;
}
set
{
kamernr = value;
}
}
public Kamer(int id, string naam, string incheck_datum, string uitcheck_datum, int hotel, int aantal_personen, int kamernr)
{
Id = id;
Naam = naam;
Incheck_datum = incheck_datum;
Uitcheck_datum = uitcheck_datum;
Hotel = hotel;
Aantal_personen = aantal_personen;
Kamernr = kamernr;
}
}
}
Uitcheckdatum and incheckdatum are the date values.
So i want, when i run the query is shows everything where are dates with null, it is for a hotel system and i want to show what bookings haven't checked in or out yet.
One way is to declare your DateTime variables as being a Nullable type, this is done by using the ? sign at the end such as this.
private DateTime? incheck_datum;
private DateTime? uitcheck_datum;
But it might be a better approach to look for, trap, and handle DB Nulls and then set default or min values like this
if (IsDBNullreader.IsDBNull(indexOfUitCheckDatum))
uitcheckdatum = DateTime.Minvalue;
else
uitcheckdatum = reader["uitcheckdatum"];
I would avoid direct initialization of an object without any previous check.
If you want to treat a DBNull value from the database as a null DateTime, there's no other option than declaring your two fields in the Kamer class using the nullable version DateTime? instead, since DateTime alone is a struct, a value type, which cannot be null. With that, you could do:
set
{
uitcheck_datum = string.IsNullOrEmpty(value) ? null : Convert.ToDateTime(value);
}
And in the loop:
while (reader.Read())
{
string incheckdatum = reader["incheckdatum"] as string;
string uitcheckdatum = reader["uitcheckdatum"] as string;
Kamer kamer = new Kamer((int)reader["boekingid"], (string)reader["naam"],
incheckdatum, uitcheckdatum, (int)reader["hotelid"],
(int)reader["aantal_gasten"], (int)reader["kamerid"]);
result.Add(kamer);
}
as saves you from possible casting exceptions. The indexer returns an instance of object. If it can't be cast to string, then null is returned.
In case you don't want to declare those fields as DateTime?, then just replace null in the set with a dummy date of your choice, e.g. DateTime.Now.
Also, make sure the string you receive from the database is a convertable string, or Convert will throw an exception. Maybe you'd want to add a try-catch to handle it.

How to properly return a value from a PropertyMethod?

First of all, sorry (AGAIN) for my bad english.
Hello. I am still pretty new to C#.NET and we are now tasked by our professor to make a simple banking system using an ADO.NET database. My only problem now is that I can't seem to return the values from the PropertyMethod I created.
Here's how it works: I log in using my auto-generated username and password, in which in the next window, I would be able to deposit or withdraw. I wanted to display in my text boxes the retrieved information from the database.
Is there a proper way to return a value from the PropertyMethod? Or could I just employ other ways to properly retrieve the values I want? Thanks for all your answers.
Here is a part of my class library which authenticates login inputs and should return the values I want:
EDIT: I tried to look at the debugger to trace what's happening to the values, but they are returning nulls.
EDIT 2: Removed unnecessary codes.
EDIT 3: Thanks for noticing my errors. I have already fixed them. My program is working fine now.
here is the propery method
#region pm
public string FinalName
{
get { return finalName; }
set { finalName = value; }
}
public string FinalUname
{
get { return finalUname; }
set { finalUname = value; }
}
public string Acnum
{
get { return acnum; }
set { acnum = value; }
}
public string Pass
{
get { return pass; }
set { pass = value; }
}
public string Actype
{
get { return actype; }
set { actype = value; }
}
public string Mname
{
get { return mname; }
set { mname = value; }
}
public string Lname
{
get { return lname; }
set { lname = value; }
}
public string Fname
{
get { return fname; }
set { fname = value; }
}
decimal bal;
public decimal Bal
{
get { return bal; }
set { bal = value; }
}
public bool Dup
{
get { return dup; }
set { dup = value; }
}
#endregion
and here is the code for authenticating login.
public bool authenticateData(string uname, string pass)
{
bool found = false;
mySqlConnection.Open();
SqlCommand readData = new SqlCommand("AuthenticateLogin", mySqlConnection);
readData.CommandType = CommandType.StoredProcedure;
readData.Parameters.Add("#Username", SqlDbType.NVarChar).Value = uname;
readData.Parameters.Add("#Password", SqlDbType.NVarChar).Value = pass;
SqlDataReader dr;
dr = readData.ExecuteReader();
while (dr.Read())
{
found = true;
Actype = dr.GetString(3);
Bal = dr.GetDecimal(5);
Acnum = dr.GetString(6);
FinalName = dr.GetString(0) + " " + dr.GetString(2) + " " + dr.GetString(1);
break;
}
mySqlConnection.Close();
return found;
}
}
}
And here is my windows form:
private void Transact_Load(object sender, EventArgs e)
{
//here is where my bug occurs
txtName.Text = da.finalName;
txtUsername.Text = da.finalUname;
txtActType.Text = da.actype;
txtBal.Text = da.Bal.ToString();
type = txtActType.Text;
}
In your windows form you're accessing properties of an object called da ... but what is that? Are you actually setting da to a class of results anywhere? Your example code doesn't show this anywhere.
In authenticateData you use a datareader to populate some properties with your results, but those properties belong to what - the class that contains the authenticateData method? What is da, and how are you expecting it to have the values of your results?

How to use a getter with a nullable?

I am reading a bunch of queries from a database. I had an issue with the queries not closing, so I added a CommandTimeout. Now, the individual queries read from the config file each time they are run.
How would I make the code cache the int from the config file only once using a static nullable and getter.
I was thinking of doing something along the lines of:
static int? var;
get{ var = null;
if (var.HasValue)
...(i dont know how to complete the rest)
My actual code:
private object QueryMethod(string item)
{
using (SqlConnection connection = new SqlConnection(item))
{
connection.Open();
using (SqlCommand sql = new SqlCommand())
{
AddSQLParms(sql);
sql.CommandTimeout = 30;
sql.CommandText = _cmdText;
sql.Connection = connection;
sql.CommandType = System.Data.CommandType.Text;
sql.ExecuteNonQuery();
}
connection.Close();
}
return false;
}
First: don't call it var !
Let's call it cached_value.
static int? cached_value;
get { return cached_value ?? cached_value = your_logic_here }
This way, the first time you call it, if it's null, it'll initialize the field. Next time you call the getter, you'll just get the value you need.
You could try something like this utilizing the Lazy<T> class:
public static class ConfigCache
{
private static Lazy<int> connectionTimeout =
new Lazy<int>(() => int.Parse(
ConfigurationManager.AppSettings["connectionTimeout"]));
public static int ConnectionTimeout
{
get { return connectionTimeout.Value; }
}
}
Usage:
sqlCmd.CommandTimeout = ConfigCache.ConnectionTimeout;
var is a system keyword - don't use it
V1 - in this version you expect config to have a value, otherwise error will occur
static int? _timeout = null;
private static int GetTimeout()
{
if (_timeout != null) return (int)_timeout;
_timeout = GetTimeoutFromConfig();
return (int)_timeout;
}
V2 - in this version you will use default value if config is empty
static int? _timeout = null;
private const int def_timeout = 120;
private static int GetTimeout()
{
if (_timeout != null) return (int)_timeout;
int? to = GetTimeoutFromConfig();
_timeout = (to ?? def_timeout);
return (int)_timeout;
}
converting from config
private int? GetTimeoutFromConfig()
{
int val;
bool converted = int.TryParse(ConfigurationManager.AppSettings["TimeoutValue"], out val);
return (converted ? val : null);
}
It sounds to be like you're asking how to use a Nullable variable.
static int? val;
get{
if (var.HasValue)
{
return val.Value;
}
else {
val = GetValFromConfig();
return val.Value;
}
}
var is a keyword in C#

object reference not set to an instance of an object

I have assigned two string array:
string[] SelectColumns = {},WhereColumns={};
Both of them are full of data items. For example SelectColumns.length = 7,WhereColumns.Length=3;
When i went to implement them i got an exception: object reference not set to an instance of an object.
I am using them in below:
for (int i = 0; i < SelectColumns.Length; i++)
{
DPS._SelectCol[i] = SelectColumns[i];
}
for (int i = 0; i < WhereColumns.Length; i++)
{
DPS._WhereCol[i] = WhereColumns[i];
}
Here DPS is the object of a class, which is given below:
public class DefaultProfileSetting
{
private string Server;
public string _Server
{
get { return Server; }
set { Server = value; }
}
private string Authentication;
public string _Authentication
{
get { return Authentication; }
set { Authentication = value; }
}
private string Login;
public string _Login
{
get { return Login; }
set { Login = value; }
}
private string Pass;
public string _Pass
{
get { return Pass; }
set { Pass = value; }
}
private string DB;
public string _DB
{
get { return DB; }
set { DB = value; }
}
private string Table;
public string _Table
{
get { return Table; }
set { Table = value; }
}
private string[] SelectCol;
public string[] _SelectCol
{
get { return SelectCol; }
set { SelectCol = value; }
}
private string[] WhereCol;
public string[] _WhereCol
{
get { return WhereCol; }
set { WhereCol = value; }
}
}
You probably have just string array reference _SelectCol but not actual array and need to instantiate the _SelectCol string array to allocate memory to its elements.
DPS._SelectCol = new string [SelectColumns.Length];
for (int i = 0; i < SelectColumns.Length; i++)
{
DPS._SelectCol[i] = SelectColumns[i];
}
I don't see anywhere in DefaultProfileSetting where you initialize the fields behind _WhereCol and _SelectCol, so these are null.
At the least you should have:
private string[] SelectCol = new string[size];
Though these should have some sort of initial population or you will get IndexOutOfBoundsException as well.
Most probably your DPS array properties are not initialized with the correct length.
You'd best place a break point and debug your solution, so that you can see for you self where exactly it goes wrong.
If you say that SelectColumns and WhereColumns are already filled with values, then i bet that DPS._SelectCol is causing problems.
You have to initialize that array at the right size. Something like :
DPS._SelectCol = new string[SelectColumns.Length];
If you leave your arrays behind and start using List then you don't have these problems anymore.

Unable to edit values in a DataGridView (using BindingList)

It seems that, due to an unknown cause, I am now unable to edit anything in my DataGridView. The DGV's ReadOnly property value is false, and all columns except for one all have the ReadOnly property set to false as well.
I'm beginning to think that it may be due to a special value I tried adding to one of my classes, one that I only wanted to be modified within the class, but still read only to the public. I don't think that value is messing with anything else, but none the less, here is the relevant portion of my code:
private void loaderWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
loadingBar.Value = e.ProgressPercentage;
if (e.UserState != null)
{
savefiles.Add((SaveFile)e.UserState);
}
}
Where savefiles is a BindingList, and where SaveFile is my class:
public class SaveFile
{
private string d_directory;
private int d_weirdnumber;
private bool d_isautosave;
private string d_fullname;
private string d_datatype;
private string d_owner;
private bool d_isquicksave;
private string d_title;
private string d_gametime;
public SaveFile() { }
public SaveFile(string directory, int weirdnumber, bool isautosave, string fullname, string datatype, string owner, bool isquicksave, string title)
{
d_directory = directory;
d_weirdnumber = weirdnumber;
d_isautosave = isautosave;
d_fullname = fullname;
d_datatype = datatype;
d_owner = owner;
d_isquicksave = isquicksave;
d_title = title;
}
public string Gametime
{
get { return d_gametime; }
}
public string Datatype
{
get { return d_datatype; }
set { d_datatype = value; }
}
public string Title
{
get { return d_title; }
set { d_title = value; }
}
public bool IsQuickSave
{
get { return d_isquicksave; }
set { d_isquicksave = value; }
}
public bool IsAutoSave
{
get { return d_isautosave; }
set { d_isautosave = value; }
}
public string Directory
{
get { return d_directory; }
set { d_directory = value; }
}
public string FullName
{
get { return d_fullname; }
set
{
d_fullname = value;
string[] split = value.Split(new char[]{'-'});
foreach (string str in split)
{
if (System.Text.RegularExpressions.Regex.IsMatch(str, "^\\d\\d:\\d\\d:\\d\\d$"))
{
d_gametime = str;
}
}
}
}
public int Weirdnumber
{
get { return d_weirdnumber; }
set { d_weirdnumber = value; }
}
public string Owner
{
get { return d_owner; }
set { d_owner = value; }
}
}
Gametime is that special property I mentioned earlier. It doesn't have a set function, but according to this, I should be in the clear, right?
Can anyone then tell me why I may not be able to edit any of the DGV cells?
EDIT: I just found out that not setting AutoGenerateColumns to false allows me to edit again, but I still don't know why.
After several hours, a friend finally took a look at it over Remote Desktop. He wrote a function to force all columns to have a non read-only status, and go figure, it worked. So we looked at the column properties in the editor, and somehow... I don't know why... they were all set to Read only. I swear I checked them 4 times before.
The lesson of this story (I guess): When in doubt, check your settings. When not in doubt, become doubtful. Otherwise, file a bug report to Microsoft :\

Categories