|
Thanks jschell.
Having an text adventure game waiting to be written does give me something to aim for.
Some books and tutorials give you examples on how each of the C# commands can be used but it's when you bring everything together in a project then I find that you learn more. Step-by-step guilds in building a program are useful and I did one of those recently.
Brian
|
|
|
|
|
I've knocked up this basic template to give you an idea what people are talking about. There is a "global" object you need to track like the player and also the current location, so you can either create these as an instance of a variable and keep a hold of them, passing them to functions\events as needed, or you could create a "static" class that will hold a reference to your player object and current location object. As I said, it's the basics, you'd need to tweak for things like containers as game objects also so you could pick up a bag, or put a small bag inside a big bag etc.
public class GameObject
{
public string Name { get; set; }
public int Weight { get; set; }
}
public abstract class Container
{
public int MaxWeight { get; set; }
public int MaxItems { get; set; }
public List<GameObject> Objects { get; private set; }
public Container() : this(0, 0)
{
}
public Container(int maxWeight, int maxItems)
{
this.Objects = new List<GameObject>();
this.MaxItems = maxItems;
this.MaxWeight = maxWeight;
}
public GameObject Find(string name)
{
return this.Objects.FirstOrDefault(o => o.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase));
}
public bool CanContain(GameObject gameObject)
{
if (this.MaxItems > 0 && Objects.Count >= this.MaxItems)
{
return false;
}
if (this.MaxWeight > 0 && Objects.Sum(o => o.Weight) + gameObject.Weight > this.MaxWeight)
{
return false;
}
return true;
}
}
public class Player : Container
{
public bool Get(Container container, string name)
{
GameObject targetObject = container.Find(name);
if (targetObject == null)
{
return false;
}
if (!this.CanContain(targetObject))
{
return false;
}
container.Objects.Remove(targetObject);
this.Objects.Add(targetObject);
return true;
}
}
public class Room : Container
{
public string Name { get; set; }
public Dictionary<string, Room> Exits { get; set; }
public Room()
{
this.Exits = new Dictionary<string, Room>();
}
}
static void Main(string[] args)
{
Player player = new Player();
Room startRoom = new Room();
startRoom.Name = "Hallway";
startRoom.Objects.Add(new GameObject { Name = "Key", Weight = 1 });
startRoom.Exits.Add("north", new Room
{
Name="Kitchen"
});
Room currentLocation = startRoom;
player.Get(currentLocation, "key");
Room room = currentLocation.Exits["north"];
if (currentLocation.Exits.ContainsKey("north"))
{
currentLocation = currentLocation.Exits["north"];
}
else
{
}
}
|
|
|
|
|
Thanks very much F-ES Sitecore for taking the time to write the code. It will be very useful and I'll learn more by studying your code.
Brian
|
|
|
|
|
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;
}
....................
|
|
|
|
|