I've created a method in a class and I want to access the streamreader sr1 from another method within the same class but I can't seem to get access to the method!
public void showSelectedFile()
{
StreamReader sr1 = new StreamReader(File.OpenRead(ReturnTxt));
ReturnContenctRD = sr1.ReadToEnd();
}
public void DisposeSR1()
{
}
Can anyone explain to me how to access/alter these methods from other functions?
sr1 is local to the showSelectedFile() method; it goes out of scope when the method returns. If you want to make it visible to the other method, you have to make it a member of your class:
StreamReader sr1;
public void showSelectedFile()
{
sr1 = new StreamReader(File.OpenRead(ReturnTxt))
ReturnContenctRD = sr1.ReadToEnd();
}
public void DisposeSR1()
{
}
If it's just a matter of disposing it properly, wrap it in a using statement:
public void showSelectedFile()
{
using (StreamReader sr1 = new StreamReader(File.OpenRead(ReturnTxt)))
{
ReturnContenctRD = sr1.ReadToEnd();
}
}
You need to store the StreamReader in a class member variable
e.g.
class YourClass
{
private StreamReader _sr1;
public void showSelectedFile()
{
_sr1 = new StreamReader(File.OpenRead(ReturnTxt));
ReturnContenctRD = _sr1.ReadToEnd();
}
public void DisposeSR1()
{
if(_sr1 != null)
_sr1.Dispose()
}
}
Related
Cosidering I can't change class ReadTheFile, is there a way how to "chain" instance methods so I don't have to reference myObject multiple times? I am looking for something like
myObject.Read().Open(param1);
I can write myObject.Open(param1).Read(); which compiles however Read() is not executed.
//myObject.Open(param1).Read(); does execute but it's executed as StreamReader method not ReadTheFile method. Overlooked VS help...
class TestT211
{
static void Main(string[] args)
{
var myObject = new ReadTheFile();
myObject.Read(myObject.Open(#"C:\file.txt"));
}
}
public class ReadTheFile
{
private int _lineCounter = 0;
private string _lineOfText;
public StreamReader Open(string path)
{
return new StreamReader(path);
}
public void Read(StreamReader sr)
{
while ((_lineOfText = sr.ReadLine()) != null) {
Console.WriteLine(_lineOfText);
}
}
}
If you want to have a syntax like a Fluent API you need to change some point of your class. First you need to have Open return the current instance and then use that instance to call Read. But this assumes that you keep the StreamReader as an internal variable of the class
public class ReadTheFile : IDisposable
{
private int _lineCounter = 0;
private string _lineOfText;
private StreamReader _sr = null;
public ReadTheFile Open(string path)
{
_sr = new StreamReader(path);
return this;
}
public void Read()
{
if(_sr == null) return;
while ((_lineOfText = _sr.ReadLine()) != null) {
Console.WriteLine(_lineOfText);
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if(_sr != null)
{
_sr.Close();
_sr = null;
}
}
}
}
and now you can write
using(ReadTheFile myObject = new ReadTheFile())
myObject.Open(#"C:\file.txt").Read();
Notice that having a StreamReader between your internal variables requires you to implement the IDisposable interface to properly close and dispose the Stream
If you want to add more functionality to class without access to it, you can use extensions. For example to use ReadTheFile to read StreamReader.
public static class StreamReaderExtension
{
public static StreamReader ReadEx(this StreamReader sr)
{
var readTheFile = new ReadTheFile();
readTheFile.Read(sr);
return sr;
}
}
and than call it with
myObject.Open(#"C:\file.txt").ReadEx();
You can add more methods, but cannot override the instance ones so you have to create a new name or new signature.
Using simple builder (it's overkill) but you could achive what you want:
class TestT211
{
static void Main(string[] args)
{
FileReaderBuilder.New.Open(#"C:\file.txt").Read();
}
}
public class ReadTheFile
{
private int _lineCounter = 0;
private string _lineOfText;
public StreamReader Open(string path)
{
return new StreamReader(path);
}
public void Read(StreamReader sr)
{
while ((_lineOfText = sr.ReadLine()) != null)
{
Console.WriteLine(_lineOfText);
}
}
}
public class FileReaderBuilder
{
private readonly ReadTheFile _file;
private StreamReader _streamReader;
private FileReaderBuilder()
{
_file = new ReadTheFile();
}
public FileReaderBuilder Open(string path)
{
_streamReader = _file.Open(path);
return this;
}
public FileReaderBuilder Read()
{
if (_streamReader == null)
{
throw new ArgumentNullException(nameof(_streamReader));
}
_file.Read(_streamReader);
return this;
}
public static FileReaderBuilder New => new FileReaderBuilder();
}
I am writing a small program in C# and at the start i noticed that Visual studio is complaining about having to use only static variables and static function calls in static functions (including the main). I have coded before, although i have to mention that i have coded before, and i cant remember being forced to use static everywhere. Here is the code:
class Program
{
string word = "asd";
static List<string> words = new List<string>();
static void Main(string[] args)
{
OpenFile();
Debug.WriteLine(words.Count);
anagram();
}
public static void OpenFile()
{
using (var fileStream = File.OpenRead("wordlist.txt"))
using (var streamReader = new StreamReader(fileStream))
{
String line;
while ((line = streamReader.ReadLine()) != null)
{
words.Add(line);
}
}
}
public void anagram()
{
Console.WriteLine(word);
}
}
I am getting the error " Error CS0120 An object reference is required for the non-static field, method, or property 'Program.anagram()' " and i just dont understand why? Also i wanted to make the words variable non-static as well but since the method is static that i am using it in it "has to be". Is there any way to avoid this?
I think i have a good understanding of what static is but i just don't want to use it here.
Any help is appreciated an thank you in advance.
You can define your logic into another class and create an instance of it and use its members.
public class MyClass
{
string word = "asd";
public List<string> Words = new List<string>();
public void OpenFile()
{
using (var fileStream = File.OpenRead("wordlist.txt"))
using (var streamReader = new StreamReader(fileStream))
{
String line;
while ((line = streamReader.ReadLine()) != null)
{
Words.Add(line);
}
}
}
public void anagram()
{
Console.WriteLine(word);
}
}
Then your main method would be like this:
static void Main(string[] args)
{
var m = new MyClass();
m.OpenFile();
Debug.WriteLine(m.Words.Count);
m.anagram();
}
You should read more about access modifiers and how static members and instance members are different.
You could write your class like this:
class Program
{
public string word = "asd";
public List<string> words = new List<string>();
static void Main(string[] args)
{
var program = new Program();
program.OpenFile();
Debug.WriteLine(program.words.Count);
program.anagram();
}
public void OpenFile()
{
using (var fileStream = File.OpenRead("wordlist.txt"))
using (var streamReader = new StreamReader(fileStream))
{
String line;
while ((line = streamReader.ReadLine()) != null)
{
this.words.Add(line);
}
}
}
public void anagram()
{
Console.WriteLine(this.word);
}
}
Static methods are generic to the class - if you want to use non-static, you need to instantiate an instance of it.
In my test scenario, I basically have two classes Program.CS and SeleniumLibrary.cs
In program.cs I want to make a new class of SeleniumLibrary.cs, but what I want to accomplish is when I do new() I want to make a new instance of my ieDriver automatically.
class Program
{
static void Main(string[] args)
{
//make SeleniumLibrary._iedriver here somehow
SeleniumLibrary.SeleniumLibrary sl = new SeleniumLibrary.SeleniumLibrary();
sl.Navigate("www.google.com");
sl.Navigate("www.nfl.com");
}
}
class SeleniumLibrary
{
private InternetExplorerDriver _ieDriver { get; set; }
private InternetExplorerDriver ieDriver
{
get
{
if (_ieDriver == null)
_ieDriver = new InternetExplorerDriver();
return _ieDriver;
}
}
public void Navigate(string url)
{
ieDriver.Navigate().GoToUrl(url);
}
}
you can see inside of my navigate method I call ieDriver, but is there a way of cleaning up the code above?
I must be misunderstanding something here because whats wrong with:
class SeleniumLibrary
{
private readonly InternetExplorerDriver _ieDriver;
public SeleniumLibrary() //Constructor
{
_ieDriver = new InternetExplorerDriver();
}
public void Navigate(string url)
{
_ieDriver.Navigate().GoToUrl(url);
}
}
This is what DUD is proposing in his answer, I'm just spelling it out.
You can create an c-tor and inside it create the ieDrive
I have a class with different methods from a Windows Form. In my test code, I used this to create a new OpenXML Document:
using (WordprocessingDocument package = WordprocessingDocument.Create(docName, WordprocessingDocumentType.Document))
But this seems not working on multiple methods. How can I fix it? It won't work without the using, so after a bit of research I found out that this class was IDisposable.
But I have 2 needs right now:
1) If the file exists, the document has to open instead of creating a new one.
2) The docName, which contains the path to the file that he's going to save, has to be reachable end used in the block as seen above.
Is there a way to do this?
This is my code right now:
using System;
using System.IO;
using System.Windows.Forms;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
namespace WordExample
{
public partial class Word : Form
{
private string _docName = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + #"\xxx2.docx";
private WordprocessingDocument _package;
private Document _doc;
private Body _body;
public Word()
{
InitializeComponent();
/*if (File.Exists(_docName))
{
_package = WordprocessingDocument.Open(_docName, false);
_doc = _package.MainDocumentPart.Document;
_body = _doc.Body;
}
else
{
_package = WordprocessingDocument.Create(_docName, WordprocessingDocumentType.Document);
_package.AddMainDocumentPart();
_doc = _package.MainDocumentPart.Document;
_body = new Body();
}*/
_package = WordprocessingDocument.Create(_docName, WordprocessingDocumentType.Document);
_package.AddMainDocumentPart();
_doc = new Document();
_body = new Body();
}
private void Word_Load(object sender, EventArgs e)
{
}
private void btnAddParagraph_Click(object sender, EventArgs e)
{
/*Paragraph p = new Paragraph();
Text t = new Text(txtTekstParagraaf.Text);
Run r = new Run();
RunProperties rPr = new RunProperties();
if (chkBold.Checked)
{
Bold b = new Bold();
rPr.Append(b);
}
if (chkItalic.Checked)
{
Italic b = new Italic();
rPr.Append(b);
}
if (chkUnderline.Checked)
{
Underline b = new Underline();
rPr.Append(b);
}
//RunProperties
//r.PrependChild<RunProperties>(rPr);
r.PrependChild(rPr);
r.AppendChild(t);
p.AppendChild(r);
_body.AppendChild(p);*/
Save();
}
private void Save()
{
_doc.AppendChild(_body);
_package.MainDocumentPart.Document = _doc;
// Save changes to the main document part.
_package.MainDocumentPart.Document.Save();
}
}
}
But this code generates an error when trying to open the created document afterwards AND when I try to open an document instead of creating one.
You can try using trenary operator here:
using (WordprocessingDocument package = File.Exists(docName) ?
WordprocessingDocument.Create(docName, WordprocessingDocumentType.Document) :
WordprocessingDocument.Open(docName, WordprocessingDocumentType.Document)) {
...
}
If the file exists, the document has to open instead of creating a new one.
So why don't you use an if statement?
if(File.Exists(docName))
{
using(var package = ..) // open file
{
...
}
}
else
{
using(var package = ..) // create file
{
...
}
}
You are not forced to instantiate variable directly in using statement. You can move creation to separate method:
private WordprocessingDocument GetPackage(string docName)
{
var docType = WordprocessingDocumentType.Document;
if (File.Exists(docName))
return WordprocessingDocument.Open(docName, docType);
return WordprocessingDocument.Create(docName, docType);
}
Now your code will look like:
using(var package = GetPackage(docName))
{
// ...
}
UPDATE: If you want to reuse disposable dependency in all methods of class (as you stated in comments) you should implement IDisposale by class which holds disposable dependency, and dispose that dependency when you are disposing class:
public class Foo : IDisposable
{
private readonly WordprocessingDocument _package;
public Foo()
{
_package = GetPackage(docName); // implemented as above
}
public void Method1()
{
// use _package without `using` block
}
public void Method2()
{
// use _package without `using` block
}
public void Dispose()
{
if (_package != null)
_package.Dispose();
}
}
Then wrap instance of Foo into using block:
using(var foo = new Foo()) // _package created here
{
foo.Method1(); // same _package instance used by both methods
foo.Method2();
} // _package will be disposed here
How can I write to a file from different class?
public class gen
{
public static string id;
public static string m_graph_file;
}
static void Main(string[] args)
{
gen.id = args[1];
gen.m_graph_file = #"msgrate_graph_" + gen.id + ".txt";
StreamWriter mgraph = new StreamWriter(gen.m_graph_file);
process();
}
public static void process()
{
<I need to write to mgraph here>
}
Pass the StreamWriter mgraph to your process() method
static void Main(string[] args)
{
// The id and m_graph_file fields are static.
// No need to instantiate an object
gen.id = args[1];
gen.m_graph_file = #"msgrate_graph_" + gen.id + ".txt";
StreamWriter mgraph = new StreamWriter(gen.m_graph_file);
process(mgraph);
}
public static void process(StreamWriter sw)
{
// use sw
}
However your code has some, difficult to understand, points:
You declare the class gen with two static vars. These vars are
shared between all instances of gen. If this is a desidered
objective, then no problem, but I am a bit puzzled.
You open the StreamWriter in your main method. This is not really
necessary given the static m_grph_file and complicates the cleanup in case your code raises
exceptions.
For example, in you gen class, (or in another class) you could write methods that work on the same file because the file name is static in the class gen
public static void process2()
{
using(StreamWriter sw = new StreamWriter(gen.m_graph_file))
{
// write your data .....
// flush
// no need to close/dispose inside a using statement.
}
}
You can pass a StreamWriter object as a parameter. Alternatively you could create a new instance inside your process method. I would also recommend wrapping your StreamWriter inside a using:
public static void process(StreamWriter swObj)
{
using (swObj)) {
// Your statements
}
}
Of course you could simply have your 'process' method like this:
public static void process()
{
// possible because of public class with static public members
using(StreamWriter mgraph = new StreamWriter(gen.m_graph_file))
{
// do your processing...
}
}
But from the design point of view this would make more sense (EDIT: full code):
public class Gen
{
// you could have private members here and these properties to wrap them
public string Id { get; set; }
public string GraphFile { get; set; }
}
public static void process(Gen gen)
{
// possible because of public class with static public members
using(StreamWriter mgraph = new StreamWriter(gen.GraphFile))
{
sw.WriteLine(gen.Id);
}
}
static void Main(string[] args)
{
Gen gen = new Gen();
gen.Id = args[1];
gen.GraphFile = #"msgrate_graph_" + gen.Id + ".txt";
process(gen);
}