This is a followup to a previous question: C# Static event null from within class
I have a class like this:
public class PlaylistModel {
public static event EventHandler PlaylistLoadError;
public static int myInt;
public static void LoadPlaylist()
{
try
{
// do some stuff, simulate exception
throw new InvalidOperationException();
}
catch(InvalidOperationException ex)
{
EventHandler handler = PlaylistLoadError;
if(handler != null)
{
PlaylistLoadError(null, null);
}
}
}
}
Else where in the program, I am setting the PlaylistLoadError EventHandler, like so:
public class MainPage {
public MainPage() {
PlaylistModel.PlaylistLoadError += MyErrorHandler;
PlaylistModel.myInt = 5;
}
public static void MyErrorHandler(object sender, EventArgs e)
{
Debug.WriteLine("There was an error");
}
}
Now, inside of LoadPlaylist, PlaylistLoadError is null and myInt is 0, despite setting them elsewhere. Later, when I create an instance of PlaylistModel, PlaylistLoadError and myInt are the correct values. So my question is this - do static functions of a class somehow access different versions of static class variables? I have checked the memory addresses of the static variables, and they are indeed different depending on if I'm inside of a non-static vs. a static function.
Static variables are static and will remain the same while the program is running unless something is called to change it.
If you want to find out what is happening I would change the field to:
private static int _myInt;
and then add:
public static int myInt
{
get { return _myInt; }
set { _myInt = value; }
}
and then add a break point at on set so you can find out when it is being changed.
Related
today I face an issue with some code I have written and really don't know where I have gone wrong, I'll keep it short and sweet basically the GetServer() method in the Faze class is returning null and I am really not sure why, but I was hoping you guys could help me with that.
I have left a few code snippets below of each class involved in the issue and where its initially called to give you a better idea on where things are going wrong.
Program.cs entry point..
static void Main(string[] args)
{
XmlConfigurator.Configure();
Faze.run();
while (true)
Console.ReadKey();
}
Faze class
public static class Faze
{
private static FazeServer fazeServer;
public static void run()
{
Console.Title = "Loading...";
fazeServer = new FazeServer("");
}
public static FazeServer GetServer()
{
return fazeServer;
}
}
FazeServer class
public sealed class FazeServer
{
private ConsoleWorker consoleWorker;
public FazeServer(string lol)
{
LoadServer();
}
private void LoadServer()
{
consoleWorker = new ConsoleWorker();
classLogger.Info("Server has been loaded.");
}
}
ConsoleWorker class
class ConsoleWorker : IDisposable
{
private readonly Timer consoleWorkerTimer;
private readonly int consoleWorkerInterval;
private static ILog classLogger;
public ConsoleWorker()
{
if (Faze.GetServer() == null)
throw new Exception("Server null..");
consoleWorkerInterval = int.Parse(Faze.GetServer().GetConfig().GetConfigElement("console.worker.interval"));
consoleWorkerTimer = new Timer(TimerElapsed, null, TimeSpan.FromMilliseconds(consoleWorkerInterval), TimeSpan.FromMilliseconds(consoleWorkerInterval));
classLogger = LogManager.GetLogger(typeof(ConsoleWorker));
}
private void TimerElapsed(object timerObject)
{
// Do something...
}
public void Dispose()
{
consoleWorkerTimer.Dispose();
}
}
After following the trace, the code that interrupts it is my null check
if (Faze.GetServer() == null)
throw new Exception("Server null..");
Before I added the if statement the line that caused an exception was
consoleWorkerInterval = int.Parse(Faze.GetServer().GetConfig().GetConfigElement("console.worker.interval"));
Why is GetServer() returning null, can anyone help?
I am after a few beers but in the class 'Faze' you have implemented a static field: 'fazeServer' and did not assign a value to it - therefore it is null.
If you would like to assign a value to 'fazeServer' static field please implement in example a static constructor for the class 'Faze' - in example: '
static Faze() { fazeServer = new FazeServer("whatEverString");}'
and that should solve the NRE.
Regards,
P.Sz.
Class fields are initialized to null by default so your code is the equivalent of:
public static class Faze
{
private static FazeServer fazeServer = null;
public static FazeServer GetServer() => fazeServer;
}
of course, calling GetServer() will return the unchaged value which is null.
If you want to initialize it yourself, use a static constructor:
public static class Faze
{
private static FazeServer fazeServer;
static Faze()
{
fazeServer = new FazeServer("");
}
}
or the field initializer:
public static class Faze
{
private static FazeServer fazeServer = new FazeServer("");
}
So it will be certain that you will get an instance when you call GetServer().
You're calling GetServer() before a value has been set in the fazeServer static variable.
The call stack is as follows:
fazeServer = new FazeServer("");
- LoadServer();
- - consoleWorker = new ConsoleWorker();
- - - if (Faze.GetServer() == null)
Or, in plain English:
fazeServer is set to the return value of new FazeServer()
new FazeServer() internally calls LoadServer()
LoadServer() internally calls new ConsoleWorker()
new ConsoleWorker() internally calls Faze.GetServer()
Faze.GetServer() returns the current value of fazeServer
So the code which sets that static variable is internally trying to read that static variable before it has finished setting it.
public class variables {
public static int edit{ get;set; }
}
And also tried:
public static int edit = 0;
public static int edit { get; set; }
public static int edits { get { return edit; } }
Using the form
form:form1 {
// Changing the value of variable to 1
private void Form1_Load(object sender, EventArgs e) {
variables.edit=1;
}
// Calling the new form where I'll use its value
private void Button_Click(object sender, EventArgs e){
form2 A=new form2();
A.Show();
}
}
form:form2{
// Showing the value of the variable in a message box
private void Form2_Load(object sender, EventArgs e){
MessageBox.show(variables.edit.ToSting());
}
}
The Message in all cases returned 0 least that call again. I need to know how to make the values initialize step as the first. I have to tab Use the many variable that keep data from one form to another and use in the load.
Make sure your class variables is static, not only the fields/properties:
public static class variables {
public static int edit = 0;
}
Another source of problem with static classes is when you use one field/property when setting another:
public static class variables {
public static int someValue = 2;
public static int other = someValue + 3;
}
AFAIK, you can't be sure of what field/property will be set first by the static constructor at runtime, unless you set the values in the static constructor, like this:
public static class variables {
static variables() {
someValue = 0;
other = someValue + 3;
}
public static int someValue;
public static int other;
}
If you are declaring static fields/properties in a really non-static class, check for the problem above, and if nothing else is changing the static field/property in another place, even inside the non-static class.
I just wanted to ask if the following code is a valid method to access the GUI from another class, or if it is bad practice. What I want to do is to write log messages into a RichTextBox in Form1.
If it's bad practice, would it be better to pass a reference of my Form1 to the other class to be able to access the RichTextBox.
I have the following code to access the GUI in my Form1 from another class:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Logger.Init(this.rtbLog);
MyOtherClass myOtherClass = new MyOtherClass();
myOtherClass.DoSomething();
}
}
public class MyOtherClass
{
public void DoSomething()
{
Logger.AppendText("text...");
Logger.AppendText("text...");
Logger.AppendText("text...");
}
}
public static class Logger
{
private static RichTextBox _rtb;
public static void Init(RichTextBox rtb)
{
_rtb = rtb;
}
public static void AppendText(String text)
{
_rtb.AppendText(text);
_rtb.AppendText(Environment.NewLine);
}
}
With Events (thanks to Ondrej):
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Logger.EntryWritten += Logger_EntryWritten;
MyOtherClass myOtherClass = new MyOtherClass();
myOtherClass.DoSomething();
}
void Logger_EntryWritten(object sender, LogEntryEventArgs args)
{
rtbLog.AppendText(args.Message);
rtbLog.AppendText(Environment.NewLine);
}
}
public class MyOtherClass
{
public void DoSomething()
{
Logger.AppendText("text...");
Logger.AppendText("text...");
Logger.AppendText("text...");
}
}
public static class Logger
{
public static event EventHandler<LogEntryEventArgs> EntryWritten;
public static void AppendText(string text)
{
var tmp = EntryWritten;
if (tmp != null)
tmp(null, new LogEntryEventArgs(text));
}
}
public class LogEntryEventArgs : EventArgs
{
private readonly String message;
public LogEntryEventArgs(String pMessage)
{
message = pMessage;
}
public String Message
{
get { return message; }
}
}
It's probably fine for a small throw-away project, but otherwise a logger should not know anything about used platform. Then it would be good to use events for example. Raise an event whenever there's a new log entry written and consumers interested in logged entries will subscribe to a delegate.
Also be careful with threads. If you log a message from a different thread than UI you will end up with an exception because you would access a GUI control from a different thread which is forbidden.
EDIT:
Something along these lines. LogEntryEventArgs is a type you have to create and you can give it properties like Message, TimeWritten, Severity, etc.
public static class Logger
{
public static event EventHandler<LogEntryEventArgs> EntryWritten;
public static void AppendText(string text)
{
var tmp = EntryWritten;
if (tmp != null)
tmp(null, new LogEntryEventArgs(text));
}
}
consumer:
Logger.EntryWritten += Logger_OnEntryWritten;
void Logger_OnEntryWritten(object sender, LogEntryEventArgs args)
{
_rtb.AppendText(args.Message);
_rtb.AppendText(Environment.NewLine);
}
Also, don't forget to invoke on a form/dispatch the body of Logger_OnEntryWritten in order to avoid cross-thread access exception (in case you are considering using threads).
I'm using delegates
in my c# windows forms application project.Using that I'm trying to remove items in a list box. I'm getting this null pointer exception and can somebody suggest a way to avoid that?
Delegate
public delegate void OrderEventDelegate (Object sender, OrderEventArgs args);
OrderEventArgs class
public class OrderEventArgs
{
private String message;
public String Message
{
get { return message; }
set { message = value; }
}
private int tableNo;
public int TableNo
{
get { return tableNo; }
set { tableNo = value; }
}
}
Class 1
public partial class Class1 : Form
{
private event OrderEventDelegate readyEvent;
public Class1(HomeForm parent, int tableNo)
{
InitializeComponent();
readyEvent -= new OrderEventDelegate(parent.readyOrder);
}
public void button_click()
{
OrderEventArgs readyOrderArg = new OrderEventArgs();
readyOrderArg.TableNo = 1;
readyOrderArg.Message = "123";
readyEvent(this, readyOrderArg);
}
}
Here readyEvent -= new OrderEventDelegate(parent.readyOrder);readyOrder() is the method which remove items in the list, which is located in the 'Homeform'.
Exception
It is possible to initialize C# events with an empty delegate. This way it can always be called safely without a null pointer check. As shown in this answer: https://stackoverflow.com/a/340618/2404788.
public delegate void OrderEventDelegate (Object sender, OrderEventArgs args) = delegate {};
If there's a possibility of something being null and you can do something about it/don't want to critically fail when it is, then check for it:
if (readyEvent != null) {
readyEvent( ... );
}
But the point here, I suppose, is that you don't want this thing to be null; so you should subscribe a handler to the event. I'm not sure why you're trying to remove a new instance of the delegate handler, but to add one you would use +=.
I am not sure if I understood the usage of delegates correctly but I would like to read delegate return value in publisher class. The example is below with description.
//Publisher class
public class ValidateAbuse
{
public delegate List<String> GetAbuseList();
public static GetAbuseList Callback;
public void Ip(string ip)
{
// I would like to read GetAbuseList value (List<String>) here. How to do that?
}
}
//Subscriber class
class Server
{
public static void Start()
{
ValidateAbuse.Callback = GetIpAbuseList;
ValidateAbuse.Ip(MyIp);
}
private static List<string> GetIpAbuseList()
{
//return List<String> to ValidateAbuse class and use return value in public void Ip(string ip) method
}
public void Ip(string ip)
{
if (Callback != null)
{
List<String> valueReturnedByCallback = Callback();
}
}
Here's a version that does not use static for ValidateAbuse and that uses the built-in Func<T> delegate.
public class ValidateAbuse
{
private Func<List<string>> callback;
public ValidateAbuse(Func<List<string>> callback)
{
this.callback = callback;
}
public void Ip(string ip)
{
var result = callback();
}
}
public class Server
{
public static void Start()
{
var validateAbuse = new ValidateAbuse(GetIpAbuseList);
validateAbuse.Ip(MyIp);
}
private static List<string> GetIpAbuseList()
{
//return List<string> to ValidateAbuse class and use return value in public void Ip(string ip) method
}
}
I recommend you avoid static since that gives you a global state, which could later give you coupling problems and also makes it hard for you to unit test.
The other answers given so far has a guard clause, checking Callback for null. Unless that is expected behaviour (that Callback is null) I would avoid this. It's better to crash early than to get hard to debug errors later on.
I would also try to make the Server non-static.
It should be as simple as:
// Ip in your code sample is missing static
public static void Ip(string ip)
{
List<string> abuseList;
if (Callback != null)
abuseList = Callback()
}
However you can avoid creating a delegate all together by using a Func:
public static Func<List<string>> Callback;
Try this: Read more from here http://msdn.microsoft.com/en-us/library/bb534960%28v=vs.110%29.aspx
internal delegate int PowerOfTwo();
void Main(){
PowerOfTwo ch = new PowerOfTwo(CheckPower);
Console.WriteLine(ch());
}
int CheckPower(){
return 2*2;
}
#Torbjörn Kalin's answer is good, but only if you have only 1 delegate you want to get the return value from. If you want to retrieve the return values of more than one delegate, this is how you do it:
//Publisher class
public class ValidateAbuse
{
public delegate List<String> GetAbuseList();
public static GetAbuseList Callback;
public void Ip(string ip)
{
foreach (GetAbuseList gal in Callback.GetInvocationList())
{
List<string> result = gal.Invoke(/*any arguments to the parameters go here*/);
//Do any processing on the result here
}
}
}
//Subscriber class
class Server
{
public static void Start()
{
//Use += to add to the delegate list
ValidateAbuse.Callback += GetIpAbuseList;
ValidateAbuse.Ip(MyIp);
}
private static List<string> GetIpAbuseList()
{
//return code goes here
return new List<String>();
}
This will invoke each delegate one after the other, and you can process the output of each delegate separately from each other.
The key here is using the += operator (not the = operator) and looping through the list that is retrieved by calling GetInvocationList() and then calling Invoke() on each delegate retrieved.
I figured this out after reading this page:
https://www.safaribooksonline.com/library/view/c-cookbook/0596003390/ch07s02.html
(altho it was partially because I already had an idea what to do, and I didn't start a free trial to read the rest)
Hope this helps!