|
Brian_TheLion wrote: I'm being drawn towards C++ as it does allow global variables compared to C#. I know that it's not good to use global variables and most variables should remind within their own class but it's not always easy to design a program like this and the program I have in mind that I want to write has many varables between classes.
Yeah, that's not how you do that. There are a few approaches that are valid from a C# point of view, but by and large a variable in the global namespace is never the answer unless the language itself forces that on you (thank you, JavaScript).
There are better tools: a static container class, a service locator, or best of all dependency injection.
Brian_TheLion wrote: I have in mind that I want to write has many varables between classes. I could write it with less classes but I want to have classes for certain purposes that can be reused in other programs. It also makes the program easier to deal with when changes are made.
Good OOP uses many, many classes that work in conjunction to build a system.I suggest you take some time to learn about SOLID Programming.
Global variables also make maintenance much, much harder in complex software. Modern IDEs have made this a little less significant, but for good, flexible software you should still prefer composability to imperative structure.
"Never attribute to malice that which can be explained by stupidity."
- Hanlon's Razor
|
|
|
|
|
Hi Nathan.
I think its more out of the frustration when a outside variable is not recognized in a class and I'm wishing it was a global variable to solve the problem. But like others have said Global variables don't make good programming code.
Brian
|
|
|
|
|
Yep, that's why I mentioned other tools. I like using MEF for this:
public class MyConfig
{
[Export("MyValue")]
public string SharedValue => "This is a value";
}
[Import]
public class MyBusinessObject
{
[Import("MyValue")]
public string ConfigValue { get; set; }
}
[Import]
public class MyOtherBusinessObject
{
[Import("MyValue")]
public string Value { get; set; }
}
This requires a little bit of bootstrapping to get MEF running, but results in a concise dependency injection mechanism without the bulkiness that some frameworks have.
"Never attribute to malice that which can be explained by stupidity."
- Hanlon's Razor
|
|
|
|
|
|
The Managed Extensibility Framework. It's a built-in way to make composable applications in C#, and can double as a dependency injection mechanism.
It's not terribly hard to use, but might be a little more overhead than you want to deal with when you're starting out.
Managed Extensibility Framework (MEF) | Microsoft Docs
"Never attribute to malice that which can be explained by stupidity."
- Hanlon's Razor
|
|
|
|
|
Thanks Nathan.
MEF looks like another branch in the NET framework tree like WPF.
It's good to know that it exists. I'll take a closer look at it with the link and code you provided thanks.
Brian
|
|
|
|
|
You know, here's a much easier way, which is basically using a global in C# without the work. I just don't advise it in general, but it does have uses:
public class SomeClass
{
public static string SomeValue = "This is a Value";
}
public class SomeOtherClass
{
public string LocalValue = SomeClass.SomeValue;
}
"Never attribute to malice that which can be explained by stupidity."
- Hanlon's Razor
|
|
|
|
|
Thanks Nathan.
Looks like a lot less code.
Is there a reason why you advise against using this type of code?
Brin
|
|
|
|
|
Largely because it's hard to maintain, and very common to forget that you stuck a static property on an object 3 years ago when you first wrote the code.
It can also lead to unexpected object states when you can change a static property from outside that object, and proper value validation logic - let alone proper state checks - is often ignored in accessors.
Lastly, it's simply not an OOP approach. It's an old-school method that is more-or-less a legacy of structured programming. Yes, static properties are very cool when used to modify the behavior of a genus of objects on the fly, but that's simply not what we're doing here. IMO if you find yourself writing software like this you're not thinking about it in a way that will lead to a good end result.
If you're just learning it's fine. Use it as a tool to make something that works. Just keep in the back of your mind that you're learning the skills to do it better the next time, and that how you conceptualize your code will have a huge impact on how good your code ends up being.
"Never attribute to malice that which can be explained by stupidity."
- Hanlon's Razor
|
|
|
|
|
|
Hi Nathan.
I just noticed your link to "SOLID Programming".
There are some good examples at that site thanks.
Brian
|
|
|
|
|
Just one quest question Nathan.
You gave me a link to SOLID Programming.
In the code examples at that site they use a dollar sign in front of a variable. What's the reason for this?
Brian
|
|
|
|
|
He's using PHP for his demo. The concept of SOLID applies to all OOP languages.
IIRC that's just a required convention in PHP, but it's been a minute since I worked with it.
"Never attribute to malice that which can be explained by stupidity."
- Hanlon's Razor
|
|
|
|
|
Your quest for the "ultimate programming language" seems to be an adventure game in itself.
Except you're ignoring all the clues left by those that have come before you.
Assembler
PC Basic
Lattice C (MS C)
dBase
Clipper
VB
Cirrus (MS Access V1)
FoxPro
...
C#
The Master said, 'Am I indeed possessed of knowledge? I am not knowing. But if a mean person, who appears quite empty-like, ask anything of me, I set it forth from one end to the other, and exhaust it.'
― Confucian Analects
|
|
|
|
|
Hi Gerry.
You wrote:
Your quest for the "ultimate programming language" seems to be an adventure game in itself.
Except you're ignoring all the clues left by those that have come before you.
Assembler
PC Basic
Lattice C (MS C)
dBase
Clipper
VB
Cirrus (MS Access V1)
FoxPro
...
C#
I'm not certain what you mean.
The commands that past languages have in common are things like If, then, else, etc
Brian
|
|
|
|
|
Dear friends;
Hello!
I want to perform the content of a variable as a C# instruction. Suppose we have a function returns a variable that contains a C# instruction and we want to perform it, like this:
void main()
{
int i= convert.int32(txtBox.text);
string TheInstruction = GenerateInstruction(i);
// here, for example TheInstruction contains something like: int s=10; or lbl.text="Hi dash: ------"; or timer.dispose(); or MessageBox.show("Wrong Number"); etc...
// and in the next line I want to perform the instruction. The question is how?
(...)
}
string GenerateInstruction(int i)
{
switch (i)
{
case 5:
theInst= "int s=" + (i*2).tostring + ";" ;
break;
case 2:
theInst= "lbl.text = \"Hi dash: " + string.Concat(Enumerable.Repeat("-", i*3)) + "\" ;" ;
break;
case 3:
theInst= "timer.dispose();";
break;
.
.
.
default:
theInst= "MessageBox.show(\"Wrong Number\");";
break;
}
return theInst;
}
Thank you in advance.
Rara
|
|
|
|
|
First: understand that C# is a strongly typed (early binding) language where all references must be resolved by the compiler before program execution. That fundamental reality means you cannot have a REPL (read-evaluate-do-stuff-and-return-results-loop) that defers execution of arbitrary code until run-time (late-binding) [^].
However, you can kind-of implement REPL in C# by using 3rd. party libraries like CShell [^], the one built into Mono, the one available in the Roslyn compiler, and by exotic code in your own DSL.
All of these methods of achieving late-binding are expensive computationally !
What you can do is create a Dictionary with Keys of whatever, and Values of executable code; I wrote about this 13 years ago: [^]; today's C# makes the syntax a bit easier:
public Dictionary<int, Action> Instructions = new Dictionary<int, Action>
{
{1, () => s = i * 2 },
{2, () => lbl.Text = $"Hi dash: {string.Concat(Enumerable.Repeat('-', i * 3))}{'\\'}"},
{3, () => timer.Dispose()},
{4, () => MessageBox.Show("Wrong Number") }
}; If you then call Instructions [4](); in a method ... voila a modal dialog.
But, note carefully: for this code to compile the variables 'i, 's, and the Label 'lbl, and the Timer 'timer must all be defined, and any variable that is not auto-initialized ('int and 'string are auto-initialized) must have an initial value set !
«Where is the Life we have lost in living? Where is the wisdom we have lost in knowledge? Where is the knowledge we have lost in information?» T. S. Elliot
modified 2-Jun-19 0:27am.
|
|
|
|
|
Thank you for your attention and reply.
(like)
|
|
|
|
|
A C# program can itself, compile text that represents a C# class (not just one line of code) and then execute that code.
You can also find other libraries that support other languages that you can "run" (compile/exectue) in a C# program.
As one example see the following. Note there are other versions and other languages.
GitHub - sebastienros/jint: Javascript Interpreter for .NET[^]
One gotcha that you should consider before going down this path is how you protect your environment from malicious code that your application runs. This might or might not be relevant to your solution but you should consider it.
|
|
|
|
|
I've got methods like this in each controller. For example, the Rules Controller has this:
public Response UpdateRuleDefinition(RuleDefintionEntity entity)
{
var response = new Response();
try
{
IRulesBL bl = GetBL();
bl.UpdateRuleDefinition(entity);
}
catch (Exception e)
{
response.Exception = e;
}
return response;
}
private IRulesBL GetBL()
{
return new RulesBL(ConnectionString, DatabaseName);
}
I also have a base Controller class called APIControllerBase. I would like to create a generic GetBL method. The return type and concrete class would need to be generic. So far I have:
public class APIControllerBase : ApiController
{
public string ConnectionString { get; private set; }
public string DatabaseName { get; private set; }
public APIControllerBase()
{
ConnectionString = Properties.Settings.Default.ConnectionString;
DatabaseName = Properties.Settings.Default.DatabaseName;
}
public T GetBL<T>() where T : new()
{
return new T();
}
I'm not sure this is the right way to create this method in the APICOntrollerBase And then, what would be the right way to call it from the controllers?
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
0) I don't understands the need for such code (maybe it's just the way you presented your example), but...
1) You'd call that method something like this: RulesBL bl = this.GetBL<RulesBL>(connstring, dbName);
2) IMHO, it seems to me that you're genericizing the wrong end of things (again, it may be the example you presented). I've done something similar, but I genericized the DAL (the base class for my BLL objects) to accept any model class I specify. My DAL contains the generic model handling, and the BLL objects (I have over 20) are concrete and simply call the DAL. I use whatever appropriate BLL object is necessary in my controllers to get/set data, and the DAL handles the models using reflection.
In my controller I have this:
DBObjectMyDB bll = new DBObjectMyDB(connstring);
SqlParameter[] parameters = new SqlParameter[]{new SqlParameter("@id", idValue)};
List<MyObject> list = bll.GetMyObect(parameters);
or this:
DBObjectMyDB bll = new DBObjectMyDB(connstring);
int recs = bll.SaveMyObject(model);
In the BLL:
public List<MyObject> GetMyObject(SqlParameter[] parameters)
{
List<MyObject> list = this.ExecuteStoredProc<MyObject>("spGetMyObject", parameters);
return list;
}
or
public int SaveMyObject(MyObject model)
{
int recs = this.ExecuteStoredProc("spSaveMyObject", model.ToSqlParameters);
return recs;
}
The DAL is where all the generic stuff is.
".45 ACP - because shooting twice is just silly" - JSOP, 2010 ----- You can never have too much ammo - unless you're swimming, or on fire. - JSOP, 2010 ----- When you pry the gun from my cold dead hands, be careful - the barrel will be very hot. - JSOP, 2013
|
|
|
|
|
The class I use in the project is a SQLite database that helps static classes. It can be called directly without using instantiation.
Originally there are a lot of related classes on the Internet. After using a class, you can't call it.
private void TextBox2_TextChanged(object sender, EventArgs e)
{
SQLiteCommand cmdInsert = new SQLiteCommand(mConn);
string sql = "INSERT INTO KD(postID,ddtime)values(@postID,@ddtime)";
SQLiteParameter[] cmdParms = new SQLiteParameter[]{
new SQLiteParameter("@postID", (textBox2.Text)),
new SQLiteParameter("@ddtime", DateTime.Now)
};
cmd.ExecuteNonQuery(sql,cmdParms);
}
The SQLiteHelper class source is as follows
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Data.SQLite;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace SQLiteQueryBrowser
{
public static class SQLiteHelper
{
public static string connectionString = "Data Source=" + Application.StartupPath + "/KDDB.db";
#region 执行数据库操作(新增、更新或删除),返回影响行数
public static int ExecuteNonQuery(SQLiteCommand cmd)
{
int result = 0;
if (connectionString == null || connectionString.Length == 0)
throw new ArgumentNullException("connectionString");
using (SQLiteConnection con = new SQLiteConnection(connectionString))
{
SQLiteTransaction trans = null;
PrepareCommand(cmd, con, ref trans, true, cmd.CommandType, cmd.CommandText);
try
{
result = cmd.ExecuteNonQuery();
trans.Commit();
}
catch (Exception ex)
{
trans.Rollback();
throw ex;
}
}
return result;
}
public static int ExecuteNonQuery(string commandText, CommandType commandType = CommandType.Text)
{
int result = 0;
if (connectionString == null || connectionString.Length == 0)
throw new ArgumentNullException("connectionString");
if (commandText == null || commandText.Length == 0)
throw new ArgumentNullException("commandText");
SQLiteCommand cmd = new SQLiteCommand();
using (SQLiteConnection con = new SQLiteConnection(connectionString))
{
SQLiteTransaction trans = null;
PrepareCommand(cmd, con, ref trans, true, commandType, commandText);
try
{
result = cmd.ExecuteNonQuery();
trans.Commit();
}
catch (Exception ex)
{
trans.Rollback();
throw ex;
}
}
return result;
}
public static int ExecuteNonQuery(string commandText, CommandType commandType = CommandType.Text, params SQLiteParameter[] cmdParms)
{
int result = 0;
if (connectionString == null || connectionString.Length == 0)
throw new ArgumentNullException("connectionString");
if (commandText == null || commandText.Length == 0)
throw new ArgumentNullException("commandText");
SQLiteCommand cmd = new SQLiteCommand();
using (SQLiteConnection con = new SQLiteConnection(connectionString))
{
SQLiteTransaction trans = null;
PrepareCommand(cmd, con, ref trans, true, commandType, commandText, cmdParms);
try
{
result = cmd.ExecuteNonQuery();
trans.Commit();
}
catch (Exception ex)
{
trans.Rollback();
throw ex;
}
}
return result;
}
#endregion
#region 执行数据库操作(新增、更新或删除)同时返回执行后查询所得的第1行第1列数据
public static object ExecuteScalar(SQLiteCommand cmd)
{
object result = 0;
if (connectionString == null || connectionString.Length == 0)
throw new ArgumentNullException("connectionString");
using (SQLiteConnection con = new SQLiteConnection(connectionString))
{
SQLiteTransaction trans = null;
PrepareCommand(cmd, con, ref trans, true, cmd.CommandType, cmd.CommandText);
try
{
result = cmd.ExecuteScalar();
trans.Commit();
}
catch (Exception ex)
{
trans.Rollback();
throw ex;
}
}
return result;
}
public static object ExecuteScalar(string commandText, CommandType commandType = CommandType.Text)
{
object result = 0;
if (connectionString == null || connectionString.Length == 0)
throw new ArgumentNullException("connectionString");
if (commandText == null || commandText.Length == 0)
throw new ArgumentNullException("commandText");
SQLiteCommand cmd = new SQLiteCommand();
using (SQLiteConnection con = new SQLiteConnection(connectionString))
{
SQLiteTransaction trans = null;
PrepareCommand(cmd, con, ref trans, true, commandType, commandText);
try
{
result = cmd.ExecuteScalar();
trans.Commit();
}
catch (Exception ex)
{
trans.Rollback();
throw ex;
}
}
return result;
}
public static object ExecuteScalar(string commandText, CommandType commandType = CommandType.Text, params SQLiteParameter[] cmdParms)
{
object result = 0;
if (connectionString == null || connectionString.Length == 0)
throw new ArgumentNullException("connectionString");
if (commandText == null || commandText.Length == 0)
throw new ArgumentNullException("commandText");
SQLiteCommand cmd = new SQLiteCommand();
using (SQLiteConnection con = new SQLiteConnection(connectionString))
{
SQLiteTransaction trans = null;
PrepareCommand(cmd, con, ref trans, true, commandType, commandText, cmdParms);
try
{
result = cmd.ExecuteScalar();
trans.Commit();
}
catch (Exception ex)
{
trans.Rollback();
throw ex;
}
}
return result;
}
#endregion
#region 执行数据库查询,返回SqlDataReader对象
public static DbDataReader ExecuteReader(SQLiteCommand cmd)
{
DbDataReader reader = null;
if (connectionString == null || connectionString.Length == 0)
throw new ArgumentNullException("connectionString");
SQLiteConnection con = new SQLiteConnection(connectionString);
SQLiteTransaction trans = null;
PrepareCommand(cmd, con, ref trans, false, cmd.CommandType, cmd.CommandText);
try
{
reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
}
catch (Exception ex)
{
throw ex;
}
return reader;
}
....................
|
|
|
|
|
I suggest you leave "God" out of this, and edit this post so that the issue you are having is clearly stated.
Rather than dump a bunch of code, describe errors or unexpected results. Show where in the code the errors occur.
Describe what you have done to isolate the errors or unexpected results.
«Where is the Life we have lost in living? Where is the wisdom we have lost in knowledge? Where is the knowledge we have lost in information?» T. S. Elliot
|
|
|
|
|
Before you read my complaints at the bottom, it is quite good code; rather readable, and already using parameterized queries. If this were in a project, I would not change it. I do have some suggestions of course.
Dhjjf wrote: It can be called directly without using instantiation. That's mostly limiting the existing class. Being able to create multiple connections and commands gives an added flexibility.
private void TextBox2_TextChanged(object sender, EventArgs e)
{
using (SQLiteConnection con = new SQLiteConnection(connectionString))
using (SQLiteCommand cmd = con.CreateCommand())
{
try
{
cmd.CommandText = "INSERT INTO KD(postID,ddtime)values(@postID,@ddtime)";
SQLiteParameter[] cmdParms = new SQLiteParameter[]{
new SQLiteParameter("@postID", (textBox2.Text)),
new SQLiteParameter("@ddtime", DateTime.Now)
};
int recordsAffected = cmd.ExecuteNonQuery(cmdParms);
Debug.Assert(recordsAffected != 1);
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
throw;
}
}
} Also, your version would be harder to use than the OO-version; the original I can wrap in a decorator-pattern, extending its functionality without changing the original classes.
Bastard Programmer from Hell
If you can't read my code, try converting it here[^]
"If you just follow the bacon Eddy, wherever it leads you, then you won't have to think about politics." -- Some Bell.
|
|
|
|
|
Three things:
1) Your error description makes no sense: "After using a class, you can't call it." You don;t use any classes, you are just calling static methods of a static class. You need to explain in a lot more detail exactly what you are doing, and what happens as a result.
2) Don't store data files - including databases - in your app folder. It will work in development, but it can fail in production because the app is installed under the "Program Files" folder which is a target for virus activity and is thus often protected from changes. See here for better ideas: Where should I store my data?[^]
3) Please learn about string.IsNullOrWhitespace rather than doing "empty string" tests yourself.
But we probably can't help you that much - this requires you app running along with your database (and probably user input) to work out what the problem might be and we have no access to any of those.
So, it's going to be up to you.
Fortunately, you have a tool available to you which will help you find out what is going on: the debugger. If you don't know how to use it, then a quick Google for "Visual Studio debugger" should give you the info you need.
Put a breakpoint on the first line in the function, and run your code through the debugger. Then look at your code, and at your data and work out what should happen manually. Then single step each line checking that what you expected to happen is exactly what did. When it isn't, that's when you have a problem, and you can back-track (or run it again and look more closely) to find out why.
Sorry, but we can't do that for you - time for you to learn a new (and very, very useful) skill: debugging!
Sent from my Amstrad PC 1640
Never throw anything away, Griff
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay...
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|