Is there any way to let multiple class share the same instance of another class?
So in my c# program i've got three class Gamelogic(A), FPSController(B), and SpawnPlayer(C).
In my case class B and C would use and alter some variables in A, in order to use the variables i'm currently instantiating A in two different classes and then use dot notation to access the variable from the instance of A, but the problem is that after A instantiated in different classes, the change in instance.variable does not share between B and C class at all.
Would static type be a good way of solving this? Or writing a main would be better.
Any suggestions would be appreciated.
There are a few ways. Here is one:
One way would be dependency injection.
You can pass the instance of A along to the constructors of B and C (or to a setter/property of B and C):
A a = new A();
B b = new B(a);
C c = new C(a);
But this doesn't allow you to change the A reference in both objects easily, which seems to be your problem.
One way to easily change the reference, is to wrap the reference in another object somehow.
A nice way to do this could be to create a Context object and pass that context object along to B and C instead of passing A. The context object plays the role as our wrapper. A context object becomes more useful if multiple variables needs to be shared between them (the shared/global state) - see the "Context pattern". Example:
public class Context {
public A a;
public ...other state you want to share...;
public Context(A a) { this.a = a; ... }
}
...
A a = new A();
Context context = new Context(a,...);
B b = new B(context);
C c = new C(context);
Depending on your situation, a static variable might be fine, however. (Or a singleton)
(In some cases passing the A-instance along to the methods of B and C, rather than to their constructor, might be better - then they also always get the current version of a (and might be more thread-safe))
It sounds like you only need to have one instance of each class and pass the data between them. There are several ways to achieve this.
Static classes are one way to go then you'd simply access/set Gamelogic.Property in each of FPSController and SpawnPlayer.
Another way would be to pass the instance of Gamelogic to FPSController and SpawnPlayer when they are created.
However, both of these couple your classes together in ways that might make future changes hard.
A third way would be to make all three classes independent and use events to change values of variables and notify the other classes of changes to these variables. This, however, would probably introduce some lag into your game as there's no guarantee that events are processes in the order you expect.
I can think of two ways, either implement the Singleton pattern for the given classes, which would ensure that only one instance exist at any given time and you can freely use it where ever, will thus achieve your purpose. Check the link by Jon skeet.
If Singleton is not an option then, create a factory, where you pass a key and for given key ensure that only same object is returned, as you can internally store the object in a Dictionary, which would always return same object and you can still create multiple object unlike Singleton
show, this my code.
public interface IMyInterface
{
void SetData(String Data);
}
public partial class Form1 : Form, IMyInterface
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Form2 frm = new Form2(this as IMyInterface);
frm.Show();
}
public void SetData(String Data)
{
textBox1.Text = Data;
}
}
public partial class Form2 : Form
{
private IMyInterface frm = null;
public Form2(IMyInterface frm)
{
InitializeComponent();
this.frm = frm;
}
private void button1_Click(object sender, EventArgs e)
{
frm.SetData(textBox1.Text);
}
}
Related
Let's say I have 3 classes:
Main class, class A, class B
and let's also say that class B has a method which needs data from class A. (the data is actually a dataview object).
objects instances of class A and class B are created in the main class regardless of the above (for them to be created in general)
what would be the best way to reach the dataview object of class A from class B?
Should I make the dataview object internal? should I make it static? should I make it internal static?
I've learned to create properties in cases like these and just "get" the object, but since it's the main form (and not Class B) which creates an object of Class A, I can't reach that property from class B.
Edit, here is a demo code:
Class Main
{
A a = new A();
B b = new B();
a.doingAClassStuff(); //Not possible unless Class A is set to public or the method is set to internal (classes are internal by default)
b.doingBClassStuff(); //Likewise
//need to get the dv object here.
//dv.rows[1].foo = bar;
}
Here above in the main class I need to get the dv object from Class B.
//each class exist in a different class file (.cs file) inside the project
Class A
{
doingAClassStuff()
{
MessageBox.Show("Hello From Class A!");
}
//here access to the dv object is also needed.
//dv.rows[5].foo = something;
}
Class A also needs to get the dv object of Class B!
//in another file as well
Class B
{
DataView dv = new Dataview(datatable1)
doingBClassStuff()
{
MessageBox.Show("Hello From Class B!");
}
}
My notes:
Making "dv" only "Internal" will not make it visible.
Making "dv" "Internal Static" will make it visible and I can work with that but I am not sure "static" has no Cons, I am not creating more than 1 instance of each class (if it matters).
I tried setting properties with "get" and get it but since the properties are public and I couldn't set them to "internal" are they public to outside of the assembly as well?
Many Thanks!
Without any additional information in regards to your requirements and restrictions, this is how I would handle it.
If you need Class A for a Class B to operate properly, you should probably provide Class B with a Class A member and either initialize it in the constructor for Class B or provide a method to set the member.
Class A should then expose through its public interface what Class B needs in a manner that makes sense for the class. i.e. don't just make the DataView public.
public class A
{
private B _b;
public A(B b)
{
_b = b;
}
void UseData()
{
_b.GetData();
}
}
Public class B
{
public DataView GetData();
}
elsewhere
B b = new B();
A a = new A(b);
what would be the best way to reach the dataview object of class A from class B?
Some options:
Pass an instance of A to a method of an instance of B
Add a property to B of type A (if the instance would be used for multiple operations
Should I make the dataview object internal? should I make it static? should I make it internal static?
Make it internal if you want it accessible to all types within the same assembly but not outside of the assembly (basically private to the assembly
Make it public if you want it available to all types inside and outside the assembly
Make it static if the data would apply to all instances of A
I can't add a comment yet but this seems similar to the following post which asks for an equivalent to friend. The top answer says to use InternalsVisibleTo to achieve somewhat similar functionality.
What is the C# equivalent of friend?
I always get tied up with small things like this... I need to access an objects properties created in class 'Login' from my welcome page class 'Default'. When I try to reference the class so that I may access the object, VS 2010 doesn't list it as available like it normally would, and forcing the request just returns an error.
My Login Class is defined like so:
public abstract class Login : System.Web.UI.UserControl
{
...
private void Login_click(object sender, EventArgs e)
{
MyObject myObject = new MyObject();
myObject.property1 = "something";
}
}
And then i wish to access myObject from my default class, like this:
public class Default : System.Web.UI.Page
{
...
private void Page_load(object sender, System.EventArgs e)
{
string someLocalVar = Login.myObject.property1;
}
}
Where property1 is a property set in the Login class. This does not work, however, and VS doesn't even recognize the Login class; instead it treats it as a reserved word of some sort. These two files are in the same project, so that shouldn't be an issue in the using section. I've accessed variables in this manner between other classes before, just not this time for some reason.
Thanks!
2 things:
Your class is abstract
Your property is probably not static
You don't actually have a property, it's a local variable
You can't instantiate an instance of an abstract class. The point of an abstract class is to create a class with some shared code that other, similar child classes can inherit. Is there a reason your class is abstract?
If your property is not static you have to create an instance of your class in order to access the property. (Which, as I describe above, you can't because it's abstract). If you make your property static, you could then do Login.MyObject without creating an instance.
In the code you supplied, your variable is local to the Login_click method, which means even if you created an instance of your class you wouldn't be able to access it.
I suggest you pick up a C# book and read up on the fundamentals.
There's a number of issues here. First, you're accessing myObject like it's a member of Login, which it isn't. It's a local variable to your Login_click method. Second, you never create an instance of Login in your Default class, so unless it's a static class or you actually create an instance of it, you're not going to be able to access any members of it.
Here's something more like what you want (I think). I've left out your class inheritance for now.
public class Login
{
MyObject object;
public Login() {
object = new MyObject();
object.property1 = "something";
}
}
public class Default {
private void Login_click(object sender, EventArgs e)
{
Login _login = new Login();
string someLocalVar = _login.object.property1;
}
}
Like others have said, you need to more carefully plan this out and strengthen your programming skills before attempting this. This is basic stuff so it shouldn't take an exorbitant amount of time -- don't worry though, we all started here.
You can put your object into a Session variable, and then Cast it back.
//in Login.aspx
MyObject myObject = new MyObject();
myObject.property1 = "something";
Session["UserObject"] = myObject;
//in default.aspx
MyObject obj = (MyObject)Session["UserObject"]
string variable = obj.property1;
Updated to reflect to my own source
I'm in process of building my first winform application in c# and I'm trying to figure out the best practice for structuring my classes to work smoothly when I use them in my forms.
I have a couple of examples which I will try to explain the best way i can.
When working with get/set variables in a class, the best practice should be something like this:
JobMove.cs
public class JobMove
{
private List<string> jobNames { get; set; }
public string Scanner;
public JobMove()
{
this.Scanner = Properties.Settings.Default.Scanner;
}
public void ListSelected(ListBox lbx)
{
foreach (string jName in this.jobNames)
{
lbx.Items.Add(jName);
}
}
public static List<string> GetCheckedJobs(ListView lw)
{
int countChecked = lw.CheckedItems.Count;
int itemCount = 0;
List<string> jList = new List<string>();
foreach (ListViewItem item in lw.CheckedItems)
{
JobInfo jobInfo = Job.Find(Convert.ToInt32(lw.Items[item.Index].SubItems[1].Text));
jList.Add(jobInfo.Name);
itemCount++;
}
return jList;
}
}
My problem is when I combine this with my forms and I call this, then I would try to do something like this:
MyForm1.cs
public partial class MyForm1 : Form
{
private void btnMoveJobs_Click(object sender, EventArgs e)
{
Properties.Settings.Default.Scanner = cbxScanners.SelectedItem.ToString();
JobMove moveJobs = new JobMove();
frmMoveJobs FrmMoveJobs = new frmMoveJobs();
FrmMoveJobs.ShowDialog();
}
}
MyForm2.cs
public partial class frmMoveJobs : Form
{
public frmMoveJobs()
{
InitializeComponent();
JobMove moveJobs = new JobMove();
lblFrom.Text = moveJobs.Scanner;
moveJobs.ListSelected(lbxJobsToMove);
cbxMjScanners.DataSource = System.Enum.GetValues(typeof(Scanners));
}
}
But when I call MyClass in MyForm2 and I want to call the DoSomethingElse method, then myString will be reset to a null value. And that makes sense to me, but how do I work around this?
I tried to figure out what to use here to get easier around these flaws in my code, but my knowledge is far too weak to just implement an easy solution.
I know I could just store this variable in Settings.settings as an example, but to me that just seems like a real overload for such a simple task.
I might just need a point in the right direction to right on what to do in this situation.
If you do a MyClass myClass = new MyClass(); then indeed - the values are independent and unrelated. If you want to share the MyClass instance then pass the MyClass instance between the forms. Perhaps:
using(var form2 = new Form2()) {
form2.SensibleName = existingMyClassInstance;
form2.ShowDialog();
}
(note the using above btw; when using ShowDialog() it is your job to make sure the form is disposed; it only gets disposed automatically if using Show())
Firstly, they're properties, not variables (the variables are the underlying data source).
Secondly, the whole point of get/set accessors is so you can get and set the value without needing helper methods.
Thirdly, and as to your problem, you're creating a new instance of the class in each form (hinted at by the new keyword) and the value of the property will be whatever it is initialised as on construction of the instance (or not.) i.e. the values of properties are not shared between different instances of the same type.
Think of the mold for a key: I can get multiple instances of the key cut from a "blueprint", but any damage that one suffers won't be reflected by the rest - they're unique in that sense.
If you want the forms to both access the same instance of that type, then you will need to stash the instance somewhere in your code which is accessible to both.
A few options:
Pass in an instance of MyClass in the form2's constructor.
Make MyClass a static property of either Form1 or Form2 and access it via that on the other form.
Make MyClass static (not recommended).
If you want to use the instance of MyClass created in MyForm1 inside of MyForm2, you need to provide it to MyForm2.
Something like this would work:
public partial class MyForm2 : Form
{
public MyForm2(MyClass given)
{
InitializeComponent();
given.DoSomethingElse();
}
}
Easy Solution:
private static string myString { get; set; }
Why: because you initialize the class again when initializing Form2 and it will create a new class. With the "static" keyword you create a property which is the same in all instances of this class.
BUT: please read some books before continuing, this would be the solution to this problem, but the source of many others. Try to understand C# and Forms first, than (or alongside with reading/learning) start coding!
this is because each of your form has a new object of "MyClass".
To achieve what you want to do use a static property... this won't be initialized and gives back the same value for each object of MyClass
it looks like this
public class MyClass {
public static string myString { get; set; }
public void ChangeMyString(string newString)
{
myString = newString;
}
public void DoSomethingElse()
{
MessageBox.Show(myString);
}
}
I'm pretty new to C# and I was trying out a few things. I have a label (named 'newLabel') in the form1.cs. I have a class named 'methods.cs'. In this class I have the method
public static void updateLabel()
what I want to do is:
public static void updateLabel()
{
newLabel.Text = "New Value";
}
but this doesn't work, probably because the method is in methods.cs and the newLabel is in form1.cs.
I had the same problem with declared variables. In the methods.cs I had the variable
int value;
but I couldn't use this variable in form1.cs. I fixed this by doing
public static int value { get; set; }
I have no idea what that did but it works, but I don't know how I can apply this trick with the label.
Could someone help me with this?
Thanks!
You should read up about OOP and encapsulation. Basically you want the form
to access private fields in another object (your class) - this is restricted by encapsulation, that's why you are running into problem - you can get around them by adding those fields and methods to the "public" interface that your class is declaring by making them public properties and methods, i.e in your example:
public int Value {get;set;}
Sometimes composition is used, i.e. in your example since your class is directly accessing the form you could have a form property on your class:
public Form ViewForm {get;set;}
It would be best if you learnt C# from tutorials, but the answer to this particular question lies with something called "scope"
Essentially, scope is the visibility of variables, classes, functions and objects. A variable marked "private" can only be seen within the thing that created it (if it's created inside a function it will always be private and any variables defined inside a function can only be used inside that function). If it's created inside a class only that class can use it.
Variables or functions denoted as public (this can only be done inside a class) can be seen from outside that class. To do that you would invoke myClass.myVariable to access the variable or myClass.myFunction() to access the function.
To denote the visibility of an object you use the keywords "public" or "private". Note: This only applies to variables and functions inside classes (it also applies to other things within classes, such as nested classes and structs, but that's outside the scope of this basic intro).
for example:
class myClass
{
private int myInt;
public void myfunction()
{
myInt = 1;
}
}
This will work, as myInt can be seen by anything inside myClass
class myOtherClass
{
private void myfunction()
{
myClass myObject = new myClass();
myObject.myInt = 2;
}
}
This will not, as myInt is private to myObject and only myObject can change it. myOtherClass does not have permission and it cannot see it.
class myOtherClassTwo
{
private void myfunction()
{
myClass myObject = new myClass();
myObject.myFunction();
}
}
This, thankfully, will work. myFunction was set as public in the myClass class, so it can be seen by anybody outside of the class.
Now the keyword static which you use has a whole different meaning. I advise you not to use it until you've learned about it as you're only adding additional complexity to your problems.
I hope this has cleared things up, though I must urge you to follow some real tutorials as these basics must be thoroughly detailed or you'll be caught out later on.
Since your updateLabel method accesses the label inside the form, correct object-oriented design would dictate that this method should be in the form, too. Then you have no problem accessing newLabel.
Technically speaking: newLabel doesn’t mean anything outside a form object. You could have several copies of your form, which would mean several copies of your newLabel; which of them should it refer to? Of course the computer won’t take a guess there; it’ll expect that you tell it which form you want to use.
The reason you couldn’t access the value variable is because it was private. If you had changed it simply to:
public static int value;
then it would have worked.
From the Form1, call the updateLabel method in the mothods class:
methods updateMethod = new methods();
newLabel.Text = updateMethod.updateLabel();
With this method in the methods class:
public static string updateLabel(){
return "New Value";
}
I have an application in C# .NET which has a MainForm and a few classes.
One of these classes receives incoming data messages from a network. I need to get these message's text appended into a multi-line textbox on the MainForm.
I can send the message to a method in the MainForm by making the method static, but then the static method cannot access the MainForm's controls.
TheIncomingDataClass.cs
namespace TheApplicationName
{
class TheIncomingDataClass
{
public void IncomingMessage(IncomingMessageType message)
{
TheApplicationName.MainForm.ReceiveMSG(message);
}
MainForm.cs
public static void ReceiveMSG(string message)
{
txtDisplayMessages.AppendText(message); //This line causes compile error
}
The compile error:
An object reference is required for the nonstatic field, method, or
property 'TheApplicationName.MainForm.txtDisplayMessages'
A static method doesn't have access to members like txtDisplayMessages because it is not a part of that instance. I suggest you do some reading on the concepts of static methods and whatnot, because that is a fairly language agnostic concept. That method would best be served by removing the static modifier, because it doesn't need to be static - it appears that it would need to be called by that particular instance of that object.
To continue the way you've been doing it, your "TheIncomingDataClass" should have a reference to the MainForm object with which it should interface. When you create an instance of this class (presumably from an instance method of MainForm), you will need to pass in a reference to this MainForm object.
class TheIncomingDataClass{
MainForm form;
public TheIncomingDataClass(MainForm form){
this.form = form;
}
}
class MainForm : Form{
MainForm(){
new TheIncomingDataClass(this);
}
}
However, as suggested by Bugs, you probably would be better off making this an event on TheIncomingDataClass and subscribing to it from MainForm.
class IncomingMessageEventArgs : EventArgs{
IncomingMessageType message;
public IncomingMessageType Message{get{return message;}}
public IncomingMessageEventArgs(IncomingMessageType message){
this.message = message;
}
}
class TheIncomingDataClass{
public event EventHandler<IncomingMessageEventArgs> MessageReceived;
protected virtual void OnMessageReceived(IncomingMessageEventArgs e){
if(MessageReceived != null)
MessageReceived(this, e);
}
public void IncomingMessage(IncomingMessageType message){
OnMessageReceived(new IncomingMessageEventArgs(message));
}
}
class MainForm : Form{
MainForm(){
new TheIncomingDataClass().MessageReceived +=
(s, e)=>txtDisplayMessages.AppendText(e.Message.ToString());
}
}
Its possible to pass in a reference to the current form like this:
public static void ReceiveMSG(string message, MainForm mainform)
{
mainform.txtDisplayMessages.AppendText(message);
}
Although as suggested an event is probably a better way of doing it.
raise an event from class which the form can subscribe to.
Just remove the static modifier, you don't need it for your purposes. Read about statics here.
You can solve this problem by removing the static keyword.
When you see "static", think: without an instance of this type.
When you call a non-static method, you must explicitly use some instance. The method can access that instance using the "this" keyword.
When you call a static method, there is no instance - you have abandoned the boundaries of OO and are now in a structural or functional programming context. If you want an instance of something, you need to bring it in as a parameter.
I think you might be taking the wrong approach on this. It sounds like you are trying to push messages to a client from an external process. There are ways to do this, but it will get complicated. My suggestion would be to have the client poll whatever process has the data periodically - maybe every 10 seconds depending on your needs. This is going to be a heck of a lot easier than pushing from server to client.
Ok here goes.
Static methods can access only static members. Your ReceiveMSG method is static. txtDisplayMessages is not and hence you cant access it.
Why does your method need to be static? Needless to say, if you remove the static keyword that will fix your problem.
Just make ReceiveMSG part of a class, create an instance of the class and then call the method on the instance.
I think you should post the kind the solution you are expecting.
Seeing as you are new to C# I will keep this as simple as possible. You should have a Program.cs file that has a single method Main (this would have been generated by Visual Studio). You will need to make it look like the following:
class Program
{
public static readonly MainForm MainForm;
static void Main()
{
Application.EnableVisualStyles();
MainForm = new MainForm(); // These two lines
Application.Run(MainForm); // are the important ones.
}
}
Now in your incoming message you will have a way to access that form.
public void IncomingMessage(IncomingMessageType message)
{
Program.MainForm.RecieveMSG(message);
}
That method in the form would then be a instance (not static) method. E.g.
public void RecieveMSG(IncomingMessageType message) // NB: No static
{
txtDisplayMessages.Text = message.Text; // Or whatever.
}
There are better ways to do it - but as a beginner I think this would be the best approach.
The difference between static and instance (instance is when you don't say static) is huge. To get to an instance method, field or property (which are collectively called members in C#) you need to have the containing instance. So:
Person p = new Person(); // You now have an instance.
p.Name = "Fred"; // You are using an instance property.
Static are the opposite, they are the same anywhere in your application (more technically within the same AppDomain - but if you are a beginner you won't need to worry about that for a while). You don't need an instance to get to them (props to codewidgets "Static methods can access only static members"). For example:
// Where Planet is a class and People is a static property.
// Somewhat confusingly the Add method is an instance - best left for the student :).
Planet.People.Add(new Person("Fred"));
Hopefully that gives you a good indication of what static and instance is and where to use them. The most important thing though is to try and avoid static members as best as you can - they can cause maintenance nightmares.
Microsoft has a whole write-up on the important concepts in regard to this.
private void FormMain_Load(object sender, EventArgs e)
{
TheIncomingDataClass.SetupControl(textBox1);
}
public class TheIncomingDataClass
{
public static TextBox textbox = new TextBox();
public static void SetupControl(TextBox txt)
{
textbox = txt;
}
public void IncomingMessage(string message)
{
textbox.Text = message;
}
}