Problem
This is partially me being my own worst enemy. I have unit tests that verify my ability to write and then retrieve all different base data types to/from a SQLite database. Among my tests I verify several different values for each data type including (but not limited to) <datatype>.MinValue and <datatype>.MaxValue.
When I write a decimal.MaxValue to the database, then try to retrieve it, I get an Overflow Exception (thanks to rounding within the database itself).
Note: I have stripped my actual classes to the bare-bones and placed them inside a test method so I could show everything more easily.
private static SQLiteConnection connection;
[TestMethod()]
public void WriteDecimal()
{
using (var cmd = new SQLiteCommand(connection))
{
cmd.CommandText = $"INSERT INTO foo(name, value) VALUES('bar', {decimal.MaxValue})";
cmd.ExecuteNonQuery();
cmd.CommandText = "SELECT * FROM foo;";
using (SQLiteDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
Console.WriteLine($"{rdr.GetInt32(0)} {rdr.GetString(1)} {rdr.GetValue(2)}");
}
}
}
}
#region Setup/Cleanup
[ClassInitialize()]
public static void Setup(TestContext context)
{
FileInfo dbFile = new FileInfo(Path.Combine(Environment.GetEnvironmentVariable("temp"), #"\Sqlite\myDb.db"));
dbFile.Directory.Create();
dbFile.Delete();
string connectionString = $"Data Source={dbFile?.FullName ?? ":memory:"}";
connection = new SQLiteConnection(connectionString);
connection.Open();
using (var cmd = new SQLiteCommand(connection))
{
cmd.CommandText = #"CREATE TABLE foo(id INTEGER PRIMARY KEY, name TEXT, value Number)";
cmd.ExecuteNonQuery();
};
}
[ClassCleanup()]
public static void Cleanup()
{
connection.Close();
}
#endregion
Output:
Message:
Test method WriteDecimal threw exception:
System.OverflowException: Value was either too large or too small for a Decimal.
Stack Trace:
Number.ThrowOverflowException(TypeCode type)
DecCalc.VarDecFromR8(Double input, DecCalc& result)
IConvertible.ToDecimal(IFormatProvider provider)
Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider)
SQLite3.GetValue(SQLiteStatement stmt, SQLiteConnectionFlags flags, Int32 index, SQLiteType typ)
SQLiteDataReader.GetValue(Int32 i)
DatabaseDirect.WriteDecimal() line 54
Workaround
I found a workaround (I just don't like it). Essentially, I let it fail, then go back and try to grab it as a Double; then convert it to what I need; because it overflowed I know it has to either be the max value or the min value:
using (SQLiteDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
decimal newVal;
try
{
newVal = (decimal)rdr.GetValue(2);
}
catch (OverflowException)
{
double val = rdr.GetDouble(2);
Type t = rdr.GetFieldType(2);
newVal = val > 0 ? decimal.MaxValue : decimal.MinValue;
}
Console.WriteLine($"{rdr.GetInt32(0)} {rdr.GetString(1)} {newVal}");
}
}
Bigger Issue (as I see it)
This isn't the only place I encounter this issue. It also happens with decimal.MinValue and ulong.MaxValue. I'm not exactly a fan of my solution simply because I just assume that if there's an overflow I need the max/min value. I'd also like to generalize it so it doesn't hard-code the min/max values I may need. Again, I found a solution; but again, it is ugly (a function that passes in the type to convert the value to and then do a switch on it...yucky).
You might not be able to do this but when I got a decimal overflow error, I tried changing my sqlite column type from decimal to real and that eliminated the error.
I have written the following in an attempt to execute a sql query and store the result in an Array:
public static ArrayList DbQueryToArry()
{
string SqlCString = myConnString;
SqlConnection connection = null;
ArrayList valuesList = new ArrayList();
connection = new SqlConnection(SqlCString);
connection.Open();
SqlCommand command = new SqlCommand("Select CLIENTNO, ACCOUNT_Purpose from audit.ACCOUNTS_AUDIT", connection);
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
valuesList.Add(Convert.ToInt32(reader[0].ToString()));
}
return valuesList;
}
But running the following
var myArray = DbQueryToArry();
Console.WriteLine(myArray.ToString());
Does not return the query result..
You will need to join them manually with string.Join or something similar:
Concatenates the elements of a specified array or the members of a
collection, using the specified separator between each element or
member.
Console.WriteLine(string.Join(",",myArray.ToArray()));
The reason why your version doesnt work is because, Console.Writeline has a bunch of overloads for different types, however it falls back to WriteLine(Object) when it can't find a specific resolution match.
The source code to WriteLine(Object value) is as follows (which can be found here).
public virtual void WriteLine(Object value) {
if (value==null) {
WriteLine();
}
else {
// Call WriteLine(value.ToString), not Write(Object), WriteLine().
// This makes calls to WriteLine(Object) atomic.
IFormattable f = value as IFormattable;
if (f != null)
WriteLine(f.ToString(null, FormatProvider));
else
WriteLine(value.ToString());
}
}
Notice how it calls value.ToString() ?
Object.ToString Method
Returns a string that represents the current object.
Remarks
Object.ToString is the major formatting method in the .NET Framework.
It converts an object to its string representation so that it is
suitable for display.
An ArrayList has no overload to ToString() that would be able to anticipate what you want to show, so it relies on the default.
The default Object.ToString() method
The default implementation of the ToString method returns the fully
qualified name of the type of the Object
Which brings me to my next point, don't use ArrayList, Use a generic array int[] or List<int> you will find it much more fun and rewarding (fun level 100)
I have 2 existing functions. One I can't edit (getServiceNames) and in the second I need to set a string (getDataTableOne).
I want to set this string with a function in the same class (getAllExceptNiServiceNames) but he gives me this error because my function i would like to edit is static.
An object reference is required non-static field, method, or property
'Queries.getAllExceptNiServiceNames()'
I can't remove the static property of the function and I also can't make a string object.
Whats the best way to fix this?
public static DataSet getDataTableOne()
{
string serviceNameFilterLineThree = getAllExceptNiServiceNames(); //ERROR
}
public static DataSet getServiceNames()
{
DataSet ds = new DataSet();
string query_select = "select test";
ds = QualityGate.fillDataset(query_select);
return ds;
}
public string getAllExceptNiServiceNames()
{
string sql = "";
DataSet ds = getServiceNames();
int i = 0;
foreach (DataRow theRow in ds.Tables[0].Rows)
{
if (i != 0)
sql += "AND ";
sql += "serviceName = '" + theRow["serviceName"].ToString() + "' ";
i++;
}
return sql;
}
You need to declare your method as static:
public static string getAllExceptNiServiceNames() { ... }
Or alternatively create an instance of your class before using the method:
var q = new Queries();
string serviceNameFilterLineThree = q.getAllExceptNiServiceNames();
I think Dan's answer might fix your immediate problem, but I'm kind of wondering if it'll help you to have a quick overview of what the static operator means; this confused me early in my CS studies, and I think I fell into a pattern of just declaring everything static because "that's the only way it worked".
In some languages, non-static functions (or "object functions" let's say) are all declared this way:
function Account.withdraw(self, amt)
self.balance -= amt;
end
That self part is a reference to the object that the method is operating on; so if you have 5 accounts, and you call bobAccount:withdraw(5), only Bob's account loses money, because bobAccount becomes self. (If you're wondering, that language is called Lua). In C#, this would just be declared this way inside the class Account...
public void withdraw(double amt) {
balance -= amt;
}
Note that there's no more "self". By default, C# methods operate on the instance of the object, and variable names are assumed to refer to variable instances declared as part of the class.
static methods are methods that are not tied to any individual object. This might be fitting if you have an operation that is very closely tied to Accounts, but doesn't just use one particular instance of them - or, if you're creating an object in a special way, as you're doing in getServiceNames(). (These can be known as "factory methods"). So if you have a static method that you want to operate on a specific object, you can either declare that method as static, or call the function on a particular instance of that object (oneObject.myFunction())
So I won't tell you exactly how you should be designing your program, but I hope giving you a better idea of how things are organized gives you a better idea in your own mind of how you want it to be.
You can not invoke a non static method from a static method. So you have to write
public static string getAllExceptNiServiceNames()
{
string sql = "";
DataSet ds = getServiceNames();
int i = 0;
foreach (DataRow theRow in ds.Tables[0].Rows)
{
if (i != 0)
sql += "AND ";
sql += "serviceName = '" + theRow["serviceName"].ToString() + "' ";
i++;
}
return sql;
}
This may solve your error.
Could I get some help explaining this answer below and how it works with the delegate. Its the answer from here: C# abstraction and database layer
...if you are stuck on the idea of using a DataReader, you could pass a delegate to the helper, which gets invoked inside of the using statements:
public string GetMySpecId(string dataId)
{
return _dbHelper.ExecuteQuery(
dr =>
{
if(dr.Read())
{
return dr[0].ToString();
}
// do whatever makes sense here.
},
#"select ""specId"" from ""MyTable"" where ""dataId"" = :dataId",
new SqlParameter("dataId", dataId));
return result.Rows[0][0].ToString();
}
You could also use a lightweight tool like Dapper to simplify some of the syntax and take care of mapping to your data types. (You'd still need to deal with opening a connection and such.)
Declaring the ExecuteQuery Method from above should look something like this:
public DataTable ExecuteQuery(Func<DataReader, DataTable> delegateMethod, string sqlQuery, SqlParameter param)
{
using (SqlConnection conn = new SqlConnection(this.MyConnectionString))
{
conn.Open();
// Declare the parameter in the query string
using (SqlCommand command = new SqlCommand(sqlQuery, conn))
{
// Now add the parameter to the parameter collection of the command specifying its type.
command.Parameters.Add(param);
command.Prepare();
// Now, add a value to it and later execute the command as usual.
command.Parameters[0].Value = dataId;
using (SqlDataReader dr = command.ExecuteReader())
{
return delegateMethod(dr);
}
}
}
}
That should be right, you may have to swap the DataReader and the DataTable in the Func, I can't remember which comes first the param types or the return type.
Here's another example of using the Func delegate, there's also the Action Delegate if you don't need a return type.
Func Delegate Reading
Normal Delegate Reading
when validating methods' input, I used to check if the argument is null, and if so I throw an ArgumentNullException. I do this for each and every argument in the list so I end up with code like this:
public User CreateUser(string userName, string password,
string Email, string emailAlerts,
string channelDescription)
{
if (string.IsNullOrEmpty(userName))
throw new ArgumentNullException("Username can't be null");
if (string.IsNullOrEmpty(Email))
throw new ArgumentNullException("Email can't be null");
//etc, etc, etc
}
Is this OK? Why should I do this? Would it be ok if I simply group all the checks and return a null value instead of throwing the exception? What is the best practice to address this situation?
PS: I want to change this, because with long methods, it gets very tedious to do so. Ideas?
Make an ArgChecker class with something like this
ArgChecker.ThrowOnStringNullOrEmpty(userName, "Username");
where ThrowOnStringNullOrEmpty is
public static void ThrowOnStringNullOrEmpty(string arg, string name)
{
if (string.IsNullOrEmpty(arg))
throw new ArgumentNullException(name + " can't be null");
}
You could also try to process a list of arguments using a params arg, like:
public static void ThrowOnAnyStringNullOrEmpty(params string[] argAndNames)
{
for (int i = 0; i < argAndName.Length; i+=2) {
ThrowOnStringNullOrEmpty(argAndNames[i], argAndNames[i+1]);
}
}
and call like this
ArgChecker.ThrowOnAnyStringNullOrEmpty(userName, "Username", Email, "email");
An approach which I use and I may have picked up from the NHibernate source is to create a static class Guard, used as follows:
public void Foo(object arg1, string arg2, int arg3)
{
Guard.ArgumentNotNull(arg1, "arg1");
Guard.ArgumentNotNullOrEmpty(arg2, "arg2");
Guard.ArgumentGreaterThan(arg3, "arg3", 0);
//etc.
}
public static class Guard
{
public static void ArgumentNotNull(object argument, string parameterName)
{
if (parameterName == null)
throw new ArgumentNullException("parameterName");
if (argument == null)
throw new ArgumentNullException(parameterName);
}
//etc.
}
This cuts down a lot of the chaff at the beginning of methods and it performs well.
You should think about the method, what it needs to do and with what data. If null values represent actual failure conditions, use exceptions. If null values are acceptable, accept them.
Think about the principles from design by contract, specifically what the preconditions to your function are, and standardize a way to enforce them (which Matt and Lou both suggest in their answers so I don't need to go into detail).
Another important thing to consider is the size of your method signatures. If you have a lot of parameters for your methods, this probably means you have bad abstractions. You can cut down on the number of parameter checks you have to make if you group parameters together in collection objects and use those objects as parameters. You can move the parameter checking to those objects instead of having to check them in every function that uses them.
So instead of passing ten related parameters to every function, figure out the few that are used in every function and package them up in an object, and include in that object methods to validate the parameters. This has the added advantage of being easy to change should the rules regarding one parameter need to be updated.
And for the C# 3.0 developers amongst us a great way to encapsulate this null checking is inside an extension method.
public void Foo(string arg1, int? arg2)
{
arg1.ThrowOnNull();
arg2.ThrowOnNull();
}
public static class extensions
{
public static void ThrowOnNull<T>(this T argument) where T : class
{
if(argument == null) throw new ArgumentNullException();
}
}
And if you wanted you could always overload that to take an argument name.
A small improvement to Lou's answer would be to use a hashtable instead, it means it checks objects aswell as just strings. Also just nicer to populate and handle in the method:
public static class ParameterChecker
{
public static void CheckForNull(Hashtable parameters)
{
foreach (DictionaryEntry param in parameters)
{
if (param.Value == null || string.IsNullOrEmpty(param.Value as string))
{
throw new ArgumentNullException(param.Key.ToString());
}
}
}
}
As you would use like:
public User CreateUser(string userName, string password, string Email, string emailAlerts, string channelDescription)
{
var parameters = new Hashtable();
parameters.Add("Username", userName);
parameters.Add("Password", password);
parameters.Add("EmailAlerts", emailAlerts);
parameters.Add("ChannelDescription", channelDescription);
ParameterChecker.CheckForNull(parameters);
// etc etc
}
I would stick with your original approach, except for just passing in the parameter name. The reason is that once you start writing those helper procedures it becomes an issue when everyone starts using different conventions for how they write the helper procedures. When someone looks over your code, they now have to check to make sure you've written the helper procedure correctly when debugging your code.
Keep checking each argument separately, though youor fingers grow weary from typing Grasshopper :) Your followers will bless you when they get the unexpected ArgumentException and are saved from a debugging run just to determine which argument failed.
My first advice to you is get ReSharper. It will tell you when there is a problem of possible null values, and when there is no need to check for them, and with the click of a mouse will add checking. Having said that...
You don't have to check for int or bool, which cannot be null.
Strings can be checked with string.IsNullOrEmpty()...
If you still decide that you want to check each and every parameter, you can either use the Command design pattern, and reflection, but your code will be unnecessarily clunky, or use the following and call it for each method:
private myType myMethod(string param1, int param2, byte[] param3)
{
CheckParameters("myMethod", {param1, param2, param3});
// rest of code...
And in your utility class put this:
///<summary>Validates method parameters</summary>
///... rest of documentation
public void CheckParameters(string methodName, List<Object> parameterValues)
{
if ( string.IsNullOrEmpty(methodName) )
throw new ArgumentException("Fire the programmer! Missing method name", "methodName"));
Type t = typeof(MyClass);
MethodInfo method = t.GetMethod(methodName);
if ( method == null )
throw new ArgumentException("Fire the programmer! Wrong method name", "methodName"));
List<ParameterInfo> params = method.GetParameters();
if ( params == null || params.Count != parameterValues.Count )
throw new ArgumentException("Fire the programmer! Wrong list of parameters. Should have " + params.Count + " parameters", "parameterValues"));
for (int i = 0; i < params.Count; i++ )
{
ParamInfo param = params[i];
if ( param.Type != typeof(parameterValues[i]) )
throw new ArgumentException("Fire the programmer! Wrong order of parameters. Error in param " + param.Name, "parameterValues"));
if ( parameterValues[i] == null )
throw new ArgumentException(param.Name + " cannot be null");
}
} // enjoy
Use an AggregateException (which is meant to contain multiple exceptions) with a list of multiple ArgumentNullException instances. Don't forget to also take advantage of the parameterName argument of ArgumentNullException which works great with nameof():
var exceptions = new List<Exceptions>();
if (firstArgument == null)
exceptions.Add(new ArgumentNullException(nameof(firstArgument), "Some optional message"));
if (secondArgument == null)
exceptions.Add(new ArgumentNullException(nameof(secondArgument), "Another optional message"));
if (exceptions.Count > 0)
throw new AggregateException(exceptions);