Static Methods and ability to access variables - c#

I am trying to access variables from a static Method. I understand the basic concept of static vs non static methods, but still do not fully understand what a static method can and cannot access.
At first I tried to put my variables at the top in the Program Class as you can see from some of my commented out lines. I could not access them from my static method which as I learned more about static made sense. But then I put the variables inside the static method. And this is what I do not understand. Inside the static method I can set fs = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite); yet once outside the if statement the sw = new StreamWriter(fs) gave me an error when I had FileStream fs inside the static method. Tried making it static as you can see by the commented out line inside the static method but that does not work either. The only way I seem to be able to access my variables is if I make them static inside the Program class (outside the static method).
class Program {
static FileStream fs;
// public bool fileopen = false;
// String filename = #"D:\Stock Trading\Test1.txt";
static void Main(string[] args) {
CreateDebugFile();
}
public static void CreateDebugFile() {
StreamWriter sw;
bool fileopen = false;
// static FileStream fs;
String filename = #
"D:\Stock Trading\Test1.txt";
if (!fileopen) {
fs = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite);
fileopen = true;
}
sw = new StreamWriter(fs);
sw.Write("Current Bar" + "\t" + "time" + "\t" + "Open" + "\t" + "Close" + "\t" + "Low" + "\t" + "High");
}
}

the static keyword from MSDN:
A non-static class can contain static methods, fields, properties, or events. The static member is callable on a class even when no instance of the class has been created. The static member is always accessed by the class name, not the instance name. Only one copy of a static member exists, regardless of how many instances of the class are created. Static methods and properties cannot access non-static fields and events in their containing type, and they cannot access an instance variable of any object unless it is explicitly passed in a method parameter.
It is more typical to declare a non-static class with some static members, than to declare an entire class as static. Two common uses of static fields are to keep a count of the number of objects that have been instantiated, or to store a value that must be shared among all instances.
Static methods can be overloaded but not overridden, because they belong to the class, and not to any instance of the class.
Although a field cannot be declared as static const, a const field is essentially static in its behavior. It belongs to the type, not to instances of the type. Therefore, const fields can be accessed by using the same ClassName.MemberName notation that is used for static fields. No object instance is required.
C# does not support static local variables (variables that are declared in method scope).
Static means that it can be accessed directly against an object without creating an instance, i.e a class, so a static member Name defined in class MyClassName can be accessed like so: MyClassName.Name(instead of new MyClassName().Name), and when you access a static member from inside that class, you can just use Name but the compiler is treating similar to you would be accessing it from outside the class.
While a static value is unchanged, any people who call that static property in an application are accessing the same instance, which can lead to concurrency issues if the value can be changed from outside the class.
Take the following example:
public class MyClassName
{
public static string FilePath = #"C:\Temp";
public static FileStream fs;
public static void CreateFileStream()
{
//creates a file stream
}
}
If two people call the same method at the same time, MyClassName.CreateFileStream() then the one who gets in there first creates a file stream and sets it to fs, then the second person creates a file stream and sets it to fs, now it is possible that someone has a reference to the file stream in the class, and the other one could be holding on to a reference to the original file stream that is no longer set on the class MyClassName.
As such you will want to pay mind to how you expose static members (not an issue in your specific example, but important to keep in mind). If you declare a static field, you should be sure to instantiate it or keep it private to the class so you can be sure it is instantiated be for using it.
In your case you are creating a new file stream every time you call that method because your bool fileopen is inside the method, anything inside of a method is only available inside that method, regardless of being static or not, and is created again every time that method is called, and you need to use the static keyword on every declaration of a field or property or method that you want to call from another static field, property, or method.
class Program {
static FileStream fs; //needs to be static
public static bool fileopen = false; //needs to be static
static String filename = #"D:\Stock Trading\Test1.txt";
//needs to be static, or this one could also be
//const if it will never change
static void Main(string[] args) {
CreateDebugFile();
}
public static void CreateDebugFile() {
//...
}
}

1. I could not access them from my static method
Static method can not use instance variable. It can only use local variable (declared inside variable) and static variable of that class or another class.
so
public static bool fileopen = false;
static String filename = #"D:\Stock Trading\Test1.txt";
would work
2. yet once outside the if statement the sw = new StreamWriter(fs) gave me an error
That's because you have not initialized the variable fs. you must initialized it before you use.
public static void CreateDebugFile() {
StreamWriter sw = null; //would remove compile time error but beware of null reference exception :)
bool fileopen = false;
String filename = #
"D:\Stock Trading\Test1.txt";
if (!fileopen) {
fs = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite);
fileopen = true;
}
sw = new StreamWriter(fs);
sw.Write("Current Bar" + "\t" + "time" + "\t" + "Open" + "\t" + "Close" + "\t" + "Low" + "\t" + "High");
}

statict classes and Methods can only access and calll to statict variables.
static FileStream fs;
/*
you can't access to this variables from a static method,
because they are declare as instance variable, even when they are nested in the same class
*/
// public bool fileopen = false;
// String filename = #"D:\Stock Trading\Test1.txt";
//you need to add the word static at begin of declaration
public static bool fileopen = false;
static string filename = #"D:\Stock Trading\Test1.txt";
Consider that static classes and variables will be alive until the program finish instead a normal class all objects will be destroyed after they use or program finish

Related

Static variable inside class

I am much confused about static variable actually i am executing below program.
class ABC
{
public static int prop { get; set; }
const int i =5;
static int j;
public ABC()
{
prop = 8;
j = 9;
Console.WriteLine("Under ABC class's constructor.");
}
public int getValue()
{
j = 6;
prop = 89;
return j;
}
}
class Program
{
static void Main(string[] args)
{
ABC obj = new ABC();
Console.WriteLine(obj.getValue());
//Console.WriteLine(ABC.j);
Console.ReadLine();
}
}
And its executing without any compile or run time error.
I have following confusions.
can we assign static variable/property inside the non static constructor?
can we assign static variable/property inside the instance method also?
If we can do assignment in above two cases for static variable/property then what is the use of static constructor?
Finally what are the locations inside a class where we can assign/initialize a static variable/property?
can we assign static variable/property inside the non static
constructor?
Yes.
can we assign static variable/property inside the instance method
also?
Yes.
If we can do assignment in above two cases for static
variable/property then what is the use of static constructor?
A static constructor is also called a type initializer. It is responsible for initializing the type it is defined in. You may use it to perform calculations that can be done upfront and are the same for all instances of that type. You'll therefore save some execution time when creating an instance because the calculation has already been done by the type initializer. Note that the type initializer runs before the type is used the first time. So you cannot deterministically tell when it actually runs. You can also not catch exceptions thrown by it because you don't actually invoke the type initializer yourself. You therefore need to be careful not to put error prone operations inside type initializers (f.e. do not do IO operations inside them).
Finally what are the locations inside a class where we can
assign/initialize a static variable/property?
From anywhere. Note that, even across threads, you can read and write to a static member from anywhere. This makes it very hard to find bugs that may occure due to a programm mutation a static somewhere in memory.
As a side note: Try to avoid having mutable static memory to keep your application simpler. If you really need to ... you should consider locking access to the static resource to prevent data races.

An object reference is required for the non-static field, method, or property 'Program.fileStream'

I have below code with error. Error message is very simple but I cant get its sense. To me looks like fileStream is being initalized when it is reading data. Can you please guide what I m missing ?
class Program
{
Stream fileStream=null;
static void Main(string[] args)
{
}
private static void ReadData()
{
using (System.Net.WebResponse tmpRes = ftpReq.GetResponse())
{
fileStream = tmpRes.GetResponseStream();
}
}
EDIT:
I have simplified this code and removed few parts. Error is on fileStream = tmpRes.GetResponseStream();
You are referencing a member variable within a static method. A member variable requires an instance of the class to be referenced where as a static method does not and can be shared across instances of the class.
Change
Stream fileStream=null;
to
static Stream fileStream=null;

Can we assign TextContext.TestDeploymentDir value to a static class data member?

I am very new to CodedUI test automation framework. I came across TestContext which has the important information regarding test result outputs and directories.
Actually i have created a static Logger class which writes output data to a .txt file. Now i want to create it under TestResults folder. Everytime i am running the test method it is creating a folder followed by some timestamp. I want to create my Results.txt file in that location.
Below is the code i am using :
public static class Logger
{
string logLocation = TestContext.TestDeploymentDir + "\\Results.txt";
static Logger() {
File.Create(logLocation);
using (var fs = new FileStream(logLocation, FileMode.Truncate))
{
}
}
public static void ResultLog(int testcasenum,String Expected,String Actual, String textResult)
{
FileInfo outtxt = new FileInfo(logLocation);
StreamWriter logline = outtxt.AppendText();
logline.WriteLine("Test Case : " + testcasenum);
logline.WriteLine("{0},{1},{2}", "Expected - "+Expected, "Actual - "+Actual, "Result - "+textResult);
// flush and close file.
logline.Flush(); logline.Close();
}
}
Now i am getting a compile time error saying A field initializer cannot reference the non-static field, method, or property TestContext.TestDeploymentDir. Not sure how to resolve this error or whether it is possible or not ?
You're going to need to mark logLocation as static since it is contained in a static class. It's kind of silly but all members of a static class do also need to be marked static. I believe this is to prevent confusion when reading larger classes where you cannot see the class declaration. Next your current error message also says TestContext.TestDeploymentDir is not marked static and you'll need to modify that as well if possible. If not you'll need to implement a singleton pattern to provide a static copy of an instance of that class. Depending on the way that class works it may or may not be possible.
Finally figured out a way to get the out path of Coded UI framework. Below is the code i have written :
public static class Logger
{
static string uripath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase) + "\\Results.txt";
public static string logLocation = new Uri(uripath).LocalPath;
static Logger() {
using (File.Create(logLocation))
{ }
using (var fs = new FileStream(logLocation, FileMode.Truncate)){}
}
public static void ResultLog(int testcasenum,String Expected,String Actual, String textResult)
{
FileInfo outtxt = new FileInfo(logLocation);
StreamWriter logline = outtxt.AppendText();
logline.WriteLine("Test Case : " + testcasenum);
logline.WriteLine("{0},{1},{2}", "Expected - "+Expected, "Actual - "+Actual, "Result - "+textResult);
// flush and close file.
logline.Flush(); logline.Close();
}
}
uripath will contain the same path as that of TestContext.TestDeploymentDir. Now Results.txt will come as an attachment in Test Explorer and we can see the output.

Store reference to method to be called later with different parameters

I need to be able to have ONE variable type store references to different methods, then call them later with different parameters, and have them return something. The methods will each have different parameter types and output types. I've tried delegates, actions and Func.
Pseudo code example below
public void Open(String directory){
File.Open(Directory);
}
public string ChangeVolume(int volume){
//Code to change volume
//return the new volume
}
public static void Main{
MyVaribleType var1 = Open;
myVaribleType var2 = ChangeVolume;
var1("C:\Windows");
Console.WriteLine(var2(100) );
}
How would I accomplish this with a single variable type?
You can hold references to the methods in collection of MethodInfo class provided by reflection APIs. To be able to call these methods you will also need to keep the references of the objects on which you want to call these methods. You can use reflection itself to invoke these methods. Reflection is slow so you can use this method only if you don't have high performance requirements.
You can't do it quite as you want to: the two methods have different signatures as #Mephy noted. You can do it using delegates, though:
public delegate FileStream OpenFileHandler(string filePath);
public delegate string ChangeVolumeHandler(FileStream stream, int volume);
class Program
{
private static FileStream Open(string filePath)
{
return File.Open(filePath, FileMode.OpenOrCreate);
}
private static string ChangeVolume(FileStream stream, int volume)
{
return "Done! Honest!";
}
static void Main(string[] args)
{
OpenFileHandler ofh = Program.Open;
ChangeVolumeHandler cvh = Program.ChangeVolume;
FileStream stream = ofh("path");
string xyzzy = cvh(stream, 100);
}
}
I'm not sure why you'd want to, but I assume that this is a rather more complex requirement that you've shown, so fine.
Note that in addition to having to use two delegates, you aloso have to pass each the items it needs to work on and that it creates (e.g. the FileStream object).
You can use an ExpandoObject:
dynamic d = new ExpandoObject();
d.ChangeVolume = new Func<int, string>(ChangeVolume);
and then call it thusly:
var result = d.ChangeVolume(volume); //ChangeVolume is type-checked at runtime.
or simply write the logic into the new dynamic property directly:
d.ChangeVolume = new Func<int, string>(x => (x * x).ToString()); // or whatever

Why C# allows initializing static class variables in non-static contructor?

Why C# allows initializing static class variables in non-static contructor? The static variables should only be allowed to be initialized on static constructors. Any ideas?
public class customer
{
public string Name;
public customer()
{
Name = "C1";
Console.WriteLine("creating customer " + Name);
}
}
class Program
{
public static customer cust;
public Program()
{
cust = new customer(); //Why is this allowed i.e. initialize a static variable in non-static constructor?
}
static void Main(string[] args)
{
Program program = new Program();
program = new Program();
Console.Read();
}
}
Don't look at it as initializing, look at it as setting.
If you would only like it to be initialized via a static constructor or at declaration, add the readonly keyword.
E.g.
public readonly static customer cust;
//Allowed
static Program()
{
cust = new customer();
}
//Not Allowed
public Program()
{
cust = new customer();
}
The short answer is there is no reason why not to allow this. Static variables can be reached anywhere from within the class (and outside, if they're public) and the constructor is no exception. This includes changing their value, or initializing them to a new value.
There are, in fact, several patterns that can take advantage of this behavior. For example, initializing a static object the first time a class is instantiated (perhaps for caching properties that are expensive to initialize but don't change in the future). Another use might be incrementing a counter to keep track of how many of these objects are alive.
With that said, you'd want to be aware of static objects in a class before initializing, and check to see if they're null before overwriting their values.
You can access and modify a static variable from any nonstatic function, it will just overwrite the value each time it is called. The opposite is not true, though - static functions can't access nonstatic variables.
It just means that the static variable is reset every time a new object is initialized. A bit weird, but the compiler allows it.

Categories

Resources