How do I declare global instances of objects?
When using C# and .NET I would do something like this:
public static program {
public static Foo MyFoo = new Foo();
static void main() {
MainForm = new MainForm(MyFoo);
}
}
however with Mono/MonoMac the main function calls NSApplication.Main and doesn't directly create any windows. How would I pass an instance of MyFoo to the main window?
Note: I am trying to avoid any references to MainClass in my windows/window controllers as that creates a tight coupling. I want to reuse the window classes in other situations hence the desire for loose coupling.
Is what I want possible with MonoMac?
thanks, Andy
Use a singleton ? Your code would then look like:
public class Foo {
public static Foo Global = new Foo ();
public Foo () { }
// rest of Foo logic
}
public class Program {
static void Main () {
MainForm = new MainForm (Foo.Global);
}
}
Related
I'm quite new to C#, and I'm using it for coding a game on Unity. I have a file named GameTools.cs that helps me with commands so that I don't have to do too much. It basically makes my code simpler and shorter. Now with the code...
//GameTools.cs
public void DoSomething() {
//some code
//some more code
}
And inside my file IntroBehavior.cs has the same void as shown above.
//IntroBehavior.cs
void Start() {
DoSomething(); //command shown above
}
Will this work? Do I have to specify something inside IntroBehavior that will be able to run code from GameTools?
in c# all functions belong to classes. They are either instance methods, or static
Instance methods operate in instances of the class
public class User{
void Login(); <<< === instance method
}
used like this
var u1 = new User();
u1.Login();
Static methods dont operate on instances of classes
public class User{
static User CreateUser(); <<<<<= static
Login(); <<< === instance method
}
Here you use them like this
var u2 = User.CreateUser();
See that you can mix the 2. If you only want static methods in a class (to be sure ) then do
public static class User{
static CreateUser(); <<<<<= static
//Login(); <<< not allowed
}
So you want
static public class GameTools{
public static void CallSomething() {
//some code
//some more code
}
}
Now in you other file
void Start() {
GameTools.CallSomething(); //command shown above
}
Of course that method has to be in a class too.
I am making a program where the objects need to chat with eachother and give orders. I'm somewhat new to C# and so I'm having trouble doing this properly. I have realized that using a static class I could achieve all I want to achieve. I understand that this is a bad approach for some reasons. I understand that I should be using dependency injection perhaps? Unfortunately I'm having trouble quite grasping how to realize that.
Below, I have created an example of what I mean by static objects that has all the "aspects" of what my program will be doing. If you feel like helping me in understanding dependency injection and it's not too much work, then you could try change my example to use dependency injection instead (and if you do, I would be very happy, as it would help me learn something I'm having trouble with)
class Program
{
static void Main(string[] args)
{
Global.worker = new Worker();
Global.employer = new Employer();
Global.reporter = new Reporter();
Global.worker.JobDone += Global.reporter.onWorkDoneR;
Global.worker.JobDone += Global.employer.onWorkDoneE;
Global.reporter.msgToUser("Initialization successful!!!");
Global.employer.startWorkDay();
Console.ReadLine();
}
}
static class Global
{
static public Worker worker;
static public Employer employer;
static public Reporter reporter;
}
class Worker
{
public delegate void EventHandler(object sender, ReporterArgs args);
public event EventHandler JobDone;
public void doJob(int joblength)
{
Global.reporter.msgToUser("Worker reporting that I'm starting work!!!");
System.Threading.Thread.Sleep(joblength*1000);
JobDone?.Invoke(this, new ReporterArgs("Work is done"));
}
}
class Employer
{
private int jobiteration = 1;
public void startWorkDay()
{
Global.worker.doJob(jobiteration);
}
public void onWorkDoneE(object sender, EventArgs args)
{
jobiteration++;
Global.worker.doJob(jobiteration);
}
}
class Reporter
{
public void msgToUser(string message)
{
Console.WriteLine(message);
}
public void onWorkDoneR(object sender, ReporterArgs args)
{
Console.WriteLine("{0} reporting: {1}", sender, args.Str);
}
}
public class ReporterArgs : EventArgs
{
private readonly string str;
public ReporterArgs(string str2lol)
{
this.str = str2lol;
}
public string Str
{
get { return this.str; }
}
}
First off, you should definitely read more references about classes in C#.
Looking at the code, the first thing I see is the way Employer class approaches the Worker.
public void startWorkDay()
{
Global.worker.doJob(jobiteration);
}
Instead of accessing a static worker object, you can treat any Worker object independently with this piece of code:
public void startWorkDay(Worker workerObjectToPerformTheJob)
{
workerObjectToPerformTheJob.doJob(jobiteration);
}
Also that is not how we write in C#:
static public Worker worker;
static public Employer employer;
static public Reporter reporter;
The correct way is: public static Foo bar;
About classes and objects:
Your program runs in the scope of static void Main(string[] args) {//stuff happens here} So when a object defined in the boundaries of Main() wants to access another object from the same scope, there is no need to define a second static class.
Now on the other hand, what if there was more classes or scopes? How can we connect them, so they can reliably access one another? Here we have two classes, foo and bar. Foo needs to hand a string variable to bar.
class foo{ string myString; }
class bar
{
void myMethod(string value)
{ print(value); }
}
Foo and Bar are in two different scopes, so in order to pass myString to myMethod(), we can implement a bridge between them.
static class Bridge
{
public static string passThis;
}
In scope 1 (maybe this was an event that was raised before a bar object was created) a Foo object gets created. This Foo object passes myString to
variable Bridge.passThis.
In scope 2 a Bar object gets created. Bar cannot access the Foo object, so we can't access objectFoo.myString. Instead we access Bridge.passThis and execute myMethod(Bridge.passThis);
I have noticed a rather weird behaviour in my application I am creating;
I have a class I defined that has a static "instance" variable of the class type.
I would assume that (as per code attached) the constructor would be called.
Alas, it is not, unless I use the Void.get in a non-static field anywhere in my code.
public class Void : TilePrototype {
public static Tile get = new Tile((int)TileEntities.Void);
public static Void instance = new Void();
public Void() {
Debug.Log("created");
id = (int)TileEntities.Void;
isBlocking = true;
register();
}
public override RenderTile render(Tile tile){
return new RenderTile(0, new Color(0, 0, 0, 0));
}
So when I have something like :
public static TileStack empty = new TileStack(Void.get, Void.get);
the Void class constructor never gets called. But, if I have:
Tile t = Void.get;
Anywhere in my code it will be called.
Why?
Thanks.
This is a really really subtle and nuanced area of C#; basically, you've stumbled into "beforefieldinit" and the difference between a static constructor and a type initializer. You can reasonably ask "when does a static constructor run?", and MSDN will tell you:
It is called automatically before the first instance is created or any static members are referenced.
Except... public static TileStack empty = new TileStack(Void.get, Void.get); isn't a static constructor! It is a static field initializer. And that has different rules, which basically are "I'll run when I must, no later, possibly sooner". To illustrate with an example: the following will not (probably) run your code, because it doesn't have to - there isn't anything demanding the field:
class Program
{
static void Main()
{
GC.KeepAlive(new Foo());
}
}
public class Foo
{
public static TileStack empty = new TileStack(Void.get, Void.get);
}
However, if we make a tiny tweak:
public class Foo
{
public static TileStack empty = new TileStack(Void.get, Void.get);
static Foo() { } // <=== added this
}
Now it has a static constructor, so it must obey the "before the first instance is created" part, which means it needs to also run the static field initializers, and so on and so on.
Without this, the static field initializer can be deferred until something touches the static fields. If any of your code actually touches empty, then it will run the static field initializer, and the instance will be created. Meaning: this would also have this effect:
class Program
{
static void Main()
{
GC.KeepAlive(Foo.empty);
}
}
public class Foo
{
public static TileStack empty = new TileStack(Void.get, Void.get);
}
This ability to defer execution of the static initialization until the static fields are actually touched is called "beforefieldinit", and it is enabled if a type has a static field initializer but no static constructor. If "beforefieldinit" isn't enabled, then the "before the first instance is created or any static members are referenced" logic applies.
Thanks to Marc Gravell's aswer I came up with this contraption (and admittedly I do like the new solution more than the old one, so thanks again!)
Modifications done to the Void class:
public class Void : TilePrototype {
public static Void instance = new Void();
public static Tile get {
get {
return new Tile(instance.id);
}
}
public Void() {
isBlocking = true;
}
public override RenderTile render(Tile tile){
return new RenderTile(0, new Color(0, 0, 0, 0));
}
}
So as You can see I made the "get" variable a property, so that it's evaluated later, when you actually need the tile, not on construction.
I've changed all "get"s this way.
Second change is in the TilePrototype:
public class TilePrototype {
public static Dictionary<int, TilePrototype> tilePrototypeDictionary = new Dictionary<int, TilePrototype>();
public static void registerPrototype(int id, TilePrototype tp){
tp.id = id;
tilePrototypeDictionary.Add(id, tp);
}
public static bool registered = false;
public static void registerAll(){
if( registered ) return;
registerPrototype(0, Void.instance);
registerPrototype(1, Air.instance);
registerPrototype(2, Floor.instance);
registerPrototype(3, Wall.instance);
(...)
Here I've added the registerPrototype and registerAll functions.
This gives me easy access to all the registered type ids (by say Wall.instance.id) as well as the other way around (from id to instance via the Dictionary)
I also have all registered things in one place, with the possibility of runtime adding more
Overall, much neater, and here I assure that all tiles are registered properly and assigned proper IDs.
Change of ID is simple and in one place and everywhere else, access to this ID is done via a short .instance.id
Thanks again for the help :)
I'm working on a Windows Forms application in C# with Visual Studio 2010.
There is a form mainForm.
mainForm contains a tree view control xmlTreeView.
There is a self-written class myClass.cs.
Now, myClass needs to access the xmlTreeView. However I don't know a) how to access the form and b) which way would be best to do that.
I tried to implement an interface following oleksii's answer but I don't get it. The main form of the application is defined like this:
public interface IMainForm {
TreeView treeView { get; }
}
public partial class mainForm : Form, IMainForm {
public TreeView treeViewControl {
get { return myTreeViewControl; }
}
// Some code here
[...]
RuleTree rt = new RuleTree(); //How do I call this with the IMainForm interface???
}
Another class RuleTree is defined like this:
class RuleTree {
private readonly IMainForm mainForm;
public RuleTree(IMainForm mainForm) {
this.mainForm = mainForm;
}
}
How do I call the constructor of RuleTree with the IMainForm interface???
I would do the following. Don't see it as code, it's just so that you can understand, you can modify it accordingly.
public class MyClass
{
public void MyMethod(YourTreeViewControl treeview)
{
// Do what you need to do here
}
}
Then in your forms code behind just instantiate MyClass and pass an instance of your treeview to it, something like this:
MyClass myClass = new MyClass();
myClass.MyMethod(tvYourTreeViewControl);
Hope this makes sense :)
One of the possible approaches would be to use dependency injection here. MyClass would have a constructor that takes a Form parameter. Thus when you create MyClass it would have the form injected. For example:
Foo
{
Foo(){}
}
Bar
{
private Foo currentFoo;
Bar(Foo foo) //dependency injection
{
currentFoo = foo;
}
public void OtherMethod()
{
//do something with currentFoo
}
}
It will be better to use interfaces (or abstract classes), so instead of Foo you could inject IFoo, this largely decouples your classes, which is a good design decision.
I have commented my code please read comments, I can make solution available as well.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
///
//Declare a static form that will accesible trhought the appication
//create form called frmMain form or any other name
//
public static frmMain MainForm { get; private set; }
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//comment out default application run
//Application.Run(new MainForm());
//create a new instance of your frmMain form
//inside your main form add a tree view
//Loacte this file "frmMain.Designer.cs"
//Change treeView1 from private to public
// public System.Windows.Forms.TreeView treeView1;
MainForm = new frmMain();
//before I show my form I'll change docking of my tree view from myClass
MyClass mine = new MyClass(); //done
MainForm.ShowDialog();
}
}
public class MyClass
{
public MyClass()
{
Program.MainForm.treeView1.Dock = DockStyle.Fill;
}
}
}
This is not possible to access asp.net server side controls into other class other then their cs class e.g
test.aspx is a page
you can access test page controls only in test.aspx.cs
Other then this class this is not possible.
I don't want to create an object because it won't affect my visible form. How can I call a method so it does its thing in the visible side of things.
public class foo
{
public void SetString(string foo)
{
label1.Text = foo;
}
}
Inside another class:
foo X = new foo();
X.SetString("testlololol");
This will set the label, but VIRTUALLY, I won't be able to see it on my form.
How can I do the same thing, but on my VISIBLE side of things?
When you create your visible form store a references to it in some static property. Then other classes can use that property to run public methods of that class.
// the original form
class MyForm()
{
// form public method
public void MyMethod() { ... }
}
// class storing the reference to a form
class MyOtherClass
{
public static Form MyForm;
public void ShowForm()
{
MyForm = new MyForm();
MyForm.Show();
}
}
// invoke form public method in this class
class YetAnotherClass
{
public void SomeMethod ()
{
MyOtherClass.MyForm.MyMethod();
}
}
You need to somehow get the instance which is visible. Work out some information path from things that already know about your form (or whatever it is) to your other code. Consider what would happen if there were two visible forms - which one would you want? That should suggest a way forward. If you know for a fact that there'll only ever be one visible instance, you could use a singleton - but I'd strongly suggest that you don't.
Bear in mind that you may not need to know of it by its full type name - if this is crossing layers, you may want to work out some interface including the action in some abstract way.
I would usually either pass a reference of my form ('foo' in this case) to the other class. Or I would store off a copy of 'foo' to some static location. If you know that there will only ever be 1 instance of 'foo' you could do something like:
public class foo
{
public static foo Current { get; private set; }
public foo()
{
foo.Current = this;
}
public void SetString(string foo)
{
label1.Text = foo;
}
}
...and...
foo.Current.SetString("testlololol");
Though thats a bit hacky IMO, and doesnt support multiple instances of 'foo'.
Your second class needs to have a reference to the instance of the class that IS visible.
public class OtherClass{
foo myFoo;
public OtherClass( foo visibleFoo )
{
myFoo = visibleFoo;
}
public void method()
{
myFoo.SetString("testlolol");
}
}