null reference on excel doc C# - c#

Hi I keep getting this error from the below code, was wondering if anyone can help.
error processing excel file: cannot perform runtime binding on a null reference
Code:
private void Import_Click(object sender, RoutedEventArgs e)
{
Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
// Show open file dialog box
Nullable<bool> result = dlg.ShowDialog();
// Process open file dialog box results
if (result == true)
{
// Open document
string filename = dlg.FileName;
Microsoft.Office.Interop.Excel.Application vExcelObj = new Microsoft.Office.Interop.Excel.Application();
try
{
Microsoft.Office.Interop.Excel.Workbook theWorkbook = vExcelObj.Workbooks.Open(filename, Type.Missing, true);
Microsoft.Office.Interop.Excel.Worksheet sheet = theWorkbook.Worksheets[1];
string vFirstName = "temp";
string vLastName = "temp";
int vIndex = 1;
while (vFirstName != "")
{
// Change the letters of the appropriate columns here!
// In my example, 'A' is first name, 'B' last name
vFirstName = sheet.get_Range("A" + vIndex.ToString()).Value.ToString(); // if i take out the exception handling the error is on this line
vLastName = sheet.get_Range("B" + vIndex.ToString()).Value.ToString();
this.SaveNewCustomer(vFirstName, vLastName);
vIndex++;
}
}
catch (Exception ex)
{
MessageBox.Show("Error processing excel file : " + ex.Message);
}
finally
{
vExcelObj.Quit();
}
}
}
private void SaveNewCustomer(string firstName, string lastName)
{
string uri = "http://localhost:8002/Service/Customer";
StringBuilder sb = new StringBuilder();
sb.Append("<Customers>");
sb.AppendLine("<FirstName>" + firstName + "</FirstName>");
sb.AppendLine("<LastName>" + lastName + "</LastName>");
sb.AppendLine("</Customers>");
string NewStudent = sb.ToString();
byte[] arr = Encoding.UTF8.GetBytes(NewStudent);
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(uri);
req.Method = "POST";
req.ContentType = "application/xml";
req.ContentLength = arr.Length;
Stream reqStrm = req.GetRequestStream();
reqStrm.Write(arr, 0, arr.Length);
reqStrm.Close();
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
reqStrm.Close();
resp.Close();
}
}
The code just takes a excel document and trys to send the data to my web service.
So I tryed using the below method but it freezes the application :S no error just hangs.
Edit attempt:
while (vFirstName != "")
{
var columnACell = sheet.get_Range("A" + vIndex.ToString());
var columnBCell = sheet.get_Range("B" + vIndex.ToString());
var columnACellValue = columnACell.Value;
var columnBCellValue = columnBCell.Value;
if (columnACellValue != null && columnBCellValue != null)
{
vFirstName = columnACellValue.ToString();
vLastName = columnBCellValue.ToString();
this.SaveNewStaff(vFirstName, vLastName); //, vPassword
vIndex++;
}
}
}

EDIT 2
Just took the code, and stepped through it. Found the problem. I think I misunderstood what was happening originally.
What's happening is that the loop while (vFirstName != "") will keep going until vFirstName is an empty string. But this will never happen! Here's why:
Everything will be fine as long as columns A and B will have values. The code will behave as expected.
When the code gets to an Excel row that doesn't have a value, it hits an empty cell, which will have .Value set to null. This causes the exception.
So the real solution here is to have the loop keep going until it hits a cell with a null value, and then exit. Kind of like this:
while (true) {
// Split the satements
var columnACell = sheet.get_Range("A" + vIndex.ToString());
var columnBCell = sheet.get_Range("B" + vIndex.ToString());
var columnACellValue = columnACell.Value;
var columnBCellValue = columnBCell.Value;
if (columnACellValue != null && columnBCellValue != null) {
vFirstName = columnACellValue.ToString();
vLastName = columnBCellValue.ToString();
} else {
break;
}
this.SaveNewCustomer(vFirstName, vLastName);
vIndex++;
};
Just tested this on my end, and it seems to work.
On a separate note, make sure that you're fully quitting Excel, because calling Excel.Quit() is often not enough. Open Task Manager and check whether there are any extra instances of EXCEL.exe floating around. To prevent those I usually kill Excel after I'm done with it (easier than properly releasing Excel's COM objects), as described in this post.
ORIGINAL POST
It sounds like there are a few options here:
The cell is empty, which means that it's .Value will be null.
The sheet is null,
get_Range() returns null -- that sounds unlikely.
Split the line into separate statements and see which one of them throws an error. That will tell you where to look further.
Judging by what you're doing -- searching the column until you find first name -- it sounds like you're running into nulls inside the cells' Values. To deal with that, I usually add a quick if-statement to test Value for null.
EDIT
Here's an example (may not compile) that will hopefully fix null values inside the cells and help to pinpoint other null-related problems. Replace the offending lines with something like this:
var columnACell = sheet.get_Range("A" + vIndex.ToString());
var columnBCell = sheet.get_Range("B" + vIndex.ToString())
var columnACellValue = columnACell.Value;
var columnBCellValue = columnBCell.Value;
if (columnACellValue != null && columnBCellValue != null) {
vFirstName = columnACellValue.ToString();
vLastName = columnBCellValue.ToString();
}
Note that I assume that your C# compiler supports implicit static typing through var.

Sheet is null. Perhaps there is only 1 worksheet? You're using Worksheets[1] which returns the second one, of course.. :)

Try to split the code that reads the value and test if it is null.
object oName = sheet.get_Range("A" + vIndex.ToString()).Value;
vFirstName = (oName == null ? string.Empty : oName.ToString();
object oLast = sheet.get_Range("B" + vIndex.ToString()).Value;
vLastName = (oLast == null ? string.Empty : oLast.ToString());
if(vFirstName.Length > 0 && vLastName.Length > 0)
this.SaveNewCustomer(vFirstName, vLastName);
And noticed that in your SaveNewStaff/Customer(....) you close the RequestStream two times.
Perhaps the second close freeze your code.
reqStrm.Close();
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
reqStrm.Close(); // <= Already closed before?

Related

Unnecessary NullReferenceException? [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 3 years ago.
Why do I get a NullReferenceException in the following code?
private string FileR ( string name )
{
string[] content = ReadSite(name, Protocol.read, url);
Request_Template newCon;
string[] final = new string[content.Length];
for (int i = 0; i < content.Length; i++)
{
if (content[i].Equals(null))
{
return "content [" + i + "] returns null";
}
newCon = JsonSerializer.Deserialize<Request_Template>(content[i]);
if (newCon.Sender.Contains(myAccount.Username))
{
newCon.Sender = "Me";
}
string sender = newCon.Sender;
string message = newCon.Message;
final[i] = sender + ":\t" + message;
}
string nFinal = string.Concat(final);
Thread.Sleep(10);
return nFinal;
}
string[] ReadSite(string filename, Protocol p, string uri)
{
Read_Template temp = new Read_Template
{
Chat = filename,
Code = key1
};
string myUrl = JsonSerializer.Serialize(temp);
WebClient web = new WebClient();
Stream stream = web.OpenRead(uri + "/" + myUrl);
int length = 0;
while (new StreamReader(stream).ReadLine() != null)
{
length++;
}
string[] content = new string[length];
using (StreamReader reader = new StreamReader(stream))
{
for (int i = 0; i < length; i++)
{
content[i] = reader.ReadLine();
}
}
return content;
}
I've tried using the debugging tools with no avail. When I ran the code, it said that the error came from string [] final = new string [content.Length];
and for (int i = 0; i < content.Length; i++).That lead me to assume that content was null. But when I used the watch window and it said that the variable content cannot be determined. How do I fix this?
I strongly suspect that the problem is actually here:
if (content[i].Equals(null))
If content[i] is genuinely null, then calling content[i].Equals will throw a NullReferenceException. That test should be written as:
if (content[i] is null)`
Or (for C# 6 or older):
if (content[i] == null)`
Now if ReadSite didn't have a bug in, you shouldn't need that check at all - because ReadSite should return an array of non-null string references. However, the way that you're populating the array is broken. You're currently:
Creating a StreamReader around the stream
Reading from the reader until you run out of data
Creating a new array of the "right" length
Creating another StreamReader around the same stream - which is by now at the end
Reading from the reader however many times you read a line originally
Because the stream is already at the end, ReadLine() is going to return null on every iteration.
Instead, you should just read once, populating a list as you go, like this:
List<string> content = new List<string>();
using (var stream = web.OpenRead(uri + "/" + myUrl))
{
using (var reader = new StreamReader(stream))
{
string line;
while ((line = reader.ReadLine()) is object)
{
content.Add(line);
}
}
}
return content;
That's returning a List<string>, so you'd want to change your ReadSite return type to List<string> or perhaps IReadOnlyList<string>. If you really need it to return an array, you could return content.ToArray() instead.
(Ideally, move to using HttpClient as well, but that's a different story.)
private string FileR ( string name )
{
// ReadSite always returns a content that has length 0 or more. string[] content will never equals null.
// TEST: string[] test = new string[0]; test == null -> False
string[] content = ReadSite(name, Protocol.read, url);
Request_Template newCon;
string[] final = new string[content.Length];
// if content.Length == 0, this loop will never occur and you wont get any NREs.
for (int i = 0; i < content.Length; i++)
{
// It is highly unlikely that a reader.ReadLine() would generate a null but
// just in case it does, use == null instead of .Equals() method. When content[i] == null, you cannot use .Equals() method since nulls dont have Equals method.
if (content[i].Equals(null))
{
return "content [" + i + "] returns null";
}
// If you have checked that content[i] is Not empty space or null, you might
//end up with newCon == null if Deserialization fails. Cover this around try / catch.
newCon = JsonSerializer.Deserialize<Request_Template>(content[i]);
// If deserialization fails, this will throw NRE because nulls wont have
// Sender as a property or array. Check if newCon == null or not. Also,
// check if Sender was correctly initialized as an array/list.. as it could
// be null. nulls wont have Contains as a method.
if (newCon.Sender.Contains(myAccount.Username))
{
newCon.Sender = "Me";
}
string sender = newCon.Sender;
string message = newCon.Message;
// This should work correctly as its dependent on content.length. If the
// loop is happening, then there is at least one final element that can be updated.
final[i] = sender + ":\t" + message;
}
string nFinal = string.Concat(final);
Thread.Sleep(10);
return nFinal;
}

Every time writes new file in c#

I am working on a c# console application. I am saving some data into a text file. Every time the programs are run it saves the data into that file without overwriting into it. Now I want to save the data into a new file every time I send a request/runs the new program.
var result = XmlDecode(soapResult);
XDocument doc = XDocument.Parse(result);
XmlReader read = doc.CreateReader();
DataSet ds = new DataSet();
ds.ReadXml(read);
read.Close();
if (ds.Tables.Count > 0 && ds.Tables["Reply"] != null && ds.Tables["Reply"].Rows.Count > 0)
{
string refNo = string.Empty;
string uniqueKey = string.Empty;
string meterNo = string.Empty;
List<string> ls = new List<string>();
if (ds.Tables["Reply"].Rows[0][0].ToString().ToUpper() == "OK")
{
if (ds.Tables["Names"] != null && ds.Tables["Names"].Rows.Count > 0)
{
uniqueKey = ds.Tables["Names"].Rows[0]["name"].ToString();
}
if (ds.Tables["NameType"] != null && ds.Tables["NameType"].Rows.Count > 0)
{
refNo = ds.Tables["NameType"].Rows[0]["name"].ToString();
}
if (ds.Tables["Meter"] != null && ds.Tables["Meter"].Rows.Count > 0)
{
if (ds.Tables["Meter"].Columns.Contains("mRID"))
{
meterNo = ds.Tables["Meter"].Rows[0]["mRID"].ToString();
processedRec++;
}
}
}
log = uniqueKey + " | " + refNo + " | " + meterNo + " | " + Environment.NewLine;
ls.Add(log);
}
File.AppendAllText(filePath, log);
How can I create a new file every time?
Any help would be highly appreciated.
Make a unique filePath. Something like this:
var filePath =$"{folderPath}\txtFile_{Guid.NewGuid()}";
This will make the file to be always unique. The guid can be replaced with something more meaningful like Unix Timestamp as well.
Create a custom file name every time and make use of File.WriteAllText (which will Creates a new file, write the contents to the file, and then closes the file. If the target file already exists, it is overwritten.) instead for File.AppendAllText
In your case the filePath should be dynamic which can be construct like this:
string basePath = ""; // this should be path to your directory in which you wanted to create the output files
string extension = ".xml";
string fileName = String.Format("{0}{1}{2}","MyFile",DateTime.Now.ToString("ddMMyy_hhmmss"),extension );
string filePath = Path.Combine(basePath,fileName);
In the above snippet the DateTime.Now.ToString("ddMMyy_hhmmss") will be the current time(at the time of execution of the code) which will be differ in each execution so the file name will differ in each run. And at some later points you can search/group files based on these common pattern.
One more thing:
In your code you have used a variable List<string> ls which is populated with all logs, and you are writing the the contents of log to the file, which contains only the last record. So the statement for writing the content should be:
File.WriteAllText(filePath, String.Join("\n",log));
or even simply
File.WriteAllLines(filePath, log);
simply make your filePath unique, for example by using Ticks
var filePath = $"app-log-{DateTime.Now.Ticks:X}.log";

Return Object if True then use in loop

I am using code to test if certain files exist and if they do, add their path and what their tab name will be (when I add them to Excel). It works but right now it is a lot of duplicated code. I want to create a method that I call and returns the object if true, and nothing if the file doesn't exist. This is the code I have:
// Add Open_SI
if (File.Exists(CurrentWorkbook.DataPath + "OPEN_SI-en-us.xlsx"))
{
FileInfo OpenSI = new FileInfo(CurrentWorkbook.DataPath + "OPEN_SI-en-us.xlsx");
if (OpenSI.Length > 5000)
File.Copy(CurrentWorkbook.DataPath + "OPEN_SI-en-us.xlsx", CurrentWorkbook.DataPath + "OPEN_SI.xlsx", true);
if (File.Exists(CurrentWorkbook.DataPath + "OPEN_SI.xlsx"))
worksheets.Add(new WorkSheets() { Path = (CurrentWorkbook.DataPath + "OPEN_SI"), TabName = "SI" });
}
// Add Pipe Sheet
if (File.Exists(CurrentWorkbook.DataPath + "Pipe_Supply-en-us.xlsx"))
{
FileInfo Pipe = new FileInfo(CurrentWorkbook.DataPath + "Pipe_Supply-en-us.xlsx");
if (Pipe.Length > 5000)
File.Copy(CurrentWorkbook.DataPath + "Pipe_Supply-en-us.xlsx", CurrentWorkbook.DataPath + "Pipe.xlsx", true);
if (File.Exists(CurrentWorkbook.DataPath + "Pipe.xlsx"))
worksheets.Add(new WorkSheets() { Path = (CurrentWorkbook.DataPath + "Pipe"), TabName = "Pipe" });
}
I repeat that code numerous times and if I make changes of course I need to make it to all of them. After that, I add them as tabs in excel with this code:
for (var i = 0; i < worksheets.Count; i++)
{
excelApp.Run("CopySheets", worksheets[i].Path, worksheets[i].TabName, CurrentWorkbook.Version)
}
How do I reduce that code to a single method call? Sorry if this seems simple but I have not created any methods that return objects on conditional statements yet.
I would return the object if true, and null otherwise.
something like this:
MyType CheckFile(string fn){
MyType myObject = new MyType();
if(File.Exists(fn))
{
//do work
return myObject;
}else{
return null;
}
}
And to use it would be something like:
string[] files = {"file1.xlsx","file2.xlsx"};
for(int i=0;i<fiels.Count;i++){
MyType obj = CheckFile(files[i]);
if(obj != null){
//object exists, do some work
}else{
//object doesn't exist, do alternative work
}
}

How to prevent empty file from being created

I have a file that is being created based on the items in a Repeater control if the radioButton for each item is "Yes". My issue that if the file is empty, it is still being created. I have tried FileName.Length > 0 and other possible solutions but I get errors that the file can not be found. I am sure the issue is within my logic but I cant see where. Any ideas?
protected void btnContinue_Click(object sender, EventArgs e)
{
string JobName;
string FileName;
StreamWriter sw;
string Name, Company, Date;
JobName = TYest + "_" + System.DateTime.Now;
JobName = JobName.Replace(":", "").Replace("/", "").Replace(" ", "");
FileName = JobName + ".txt";
sw = new StreamWriter(C: +"/" + FileName, false, Encoding.GetEncoding(1250));
foreach ( RepeaterItem rpItems in rpGetData.Items )
{
RadioButtonList rbYesNo = (RadioButtonList)rpItems.FindControl("rbBadge");
if ( rbYesNo.SelectedItem.Text == "Yes" )
{
Label rName = (Label)rpItems.FindControl("lblName");
Label rCompany = (Label)rpItems.FindControl("lblCompany");
Label rFacilityName = (Label)rpItems.FindControl("lblFacility_Hidden");
Name = rName.Text;
Company = rCompany.Text;
Date = System.DateTime.Now.ToString("MM/dd/yyyy");
sw.WriteLine("Name," + Name);
sw.WriteLine("Company," + Company);
sw.WriteLine("Date," + Date);
sw.WriteLine("*PRINTLABEL");
}
sw.Flush();
sw.Dispose();
if ( File.Exists("C:/" + FileName) )
{
try
{
File.Copy(+"C:/" + FileName, LoftwareDropPath + FileName, true);
}
catch ( Exception ex )
{
string msgE = "Error";
msgE += ex.Message;
throw new Exception(msgE);
}
}
else
{
//Do something if temp file not created properly
lblMessage.Text = "An error has occurred. Plese see your host to get a printed name badge.";
}
MessageBox messageBox = new MessageBox();
messageBox.MessageTitle = "Printed?";
messageBox.MessageText = "If not, please see host.";
Literal1.Text = messageBox.Show(this);
}
}
sounds like you want to detect if a file is empty. Use:
long length = new System.IO.FileInfo(path).Length;
if(length == 0)....
FileName.Length just tells you how long the file name is - not usefule
Why not check if the file exists first? That should solve your exception problems! If you want to know if the file is empty I would recommend checking what you're writing to the file and making sure it's not all empty and THEN write to the file if you actually have content?
if(File.Exists(File))
{
if(new FileInfo(File).Length > 0)
{
//Do Stuff.
}
}
How about this:
StreamWriter sw = null;
string Name, Company, Date;
JobName = TYest + "_" + System.DateTime.Now;
JobName = JobName.Replace(":", "").Replace("/", "").Replace(" ", "");
FileName = #"C:\" + JobName + ".txt";
try
{
foreach (RepeaterItem rpItems in rpGetData.Items)
{
RadioButtonList rbYesNo = (RadioButtonList)rpItems.FindControl("rbBadge");
if (rbYesNo.SelectedItem.Text == "Yes")
{
if (null == sw)
sw = new StreamWriter(FileName, false, Encoding.GetEncoding(1250));
Label rName = (Label)rpItems.FindControl("lblName");
Label rCompany = (Label)rpItems.FindControl("lblCompany");
Label rFacilityName = (Label)rpItems.FindControl("lblFacility_Hidden");
Name = rName.Text;
Company = rCompany.Text;
Date = System.DateTime.Now.ToString("MM/dd/yyyy");
sw.WriteLine("Name," + Name);
sw.WriteLine("Company," + Company);
sw.WriteLine("Date," + Date);
sw.WriteLine("*PRINTLABEL");
}
}
finally
{
if (null != sw)
{
sw.Flush();
sw.Dispose();
}
}
Build your FileName completely once so that you know it is always the same. Then only create your StreamWriter if something is going to be written. Also, use a try..finally to make sure your code to free your resources is always hit.
You should change it to only write and create the file when you have some data to write.
A simple way of doing this is to store everything memory with something like a StringBuilder, then afterwards write the contents of the string builder to the file if there is something to write:
var sb = new StringBuilder();
foreach (RepeaterItem rpItems in rpGetData.Items)
{
RadioButtonList rbYesNo = (RadioButtonList)rpItems.FindControl("rbBadge");
if (rbYesNo.SelectedItem.Text == "Yes")
{
// ..omitted..
sb.AppendLine("Name," + Name);
sb.AppendLine("Company," + Company);
sb.AppendLine("Date," + Date);
sb.AppendLine("*PRINTLABEL");
}
}
if (sb.Length > 0)
{
File.WriteAllText(FileName, sb.ToString(), Encoding.GetEncoding(1250));
}
You can check whether any items are eligible for saving before opening the stream writer like this:
var itemsToBeSaved = rpGetData.Items
Where(ri => ((RadioButtonList)ri.FindControl("rbBadge")).SelectedItem.Text == "Yes");
if (itemsToBeSaved.Any()) {
string path = #"C:\" + FileName;
using (var sw = new StreamWriter(path, false, Encoding.GetEncoding(1250))) {
foreach (RepeaterItem rpItems in itemsToBeSaved) {
Label rName = (Label)rpItems.FindControl("lblName");
Label rCompany = (Label)rpItems.FindControl("lblCompany");
Label rFacilityName = (Label)rpItems.FindControl("lblFacility_Hidden");
Name = rName.Text;
Company = rCompany.Text;
Date = System.DateTime.Now.ToString("MM/dd/yyyy");
sw.WriteLine("Name," + Name);
sw.WriteLine("Company," + Company);
sw.WriteLine("Date," + Date);
sw.WriteLine("*PRINTLABEL");
}
} // Flushes, Closes und Disposes the stream automatically.
}
The first statement prepares a filtered enumeration of repeater items containing only the ones to be saved. itemsToBeSaved.Any() tests if this enumeration contains at least one item. This enumeration is then reused in the foreach statement. Therefore it is not necessary to check the conditions again.
The using statement takes care of closing the stream in all situations, even if an exception should occur while writing to the file. I also declared the stream writer in the using statement. Therefore you can delete your declaration StreamWriter sw = null;.
Also note the expression #"C:\" + FileName. The # makes the string constant a verbatim string. This means that the usual escape character '\' loses its meaning and is used as is. Path.Combine(...) does not work here, since it does not add the path separator after a drive letter.

Proper way to declare a variable for use outside of try block

So I am fairly new to C# (not programming in general) and I wrote some code with nearly Zero error handling to make a proof of concept for running in VS only. Now I am getting ready to build some error handling into the application so that the application can be deployed. So now I am having issues figuring out how/where to declare variables so that I can properly configure a Try Catch block.
So with primitive types I just create the variable outside of the block
Before:
String TheString = "Some times I break";
SomeFunctionThatBreaks(TheString);
SomeFunctionThatDoesntBreak(TheString);
After:
String TheString ="";
Try
{
TheString="Some Times I break";
SomeFunctionThatBreaks(TheString);
}
Catch
{
MessageBox.Show("Error")
return false;
}
SomeFunctionThatDoesntBreak(TheString);
However with complex types such as FileStream I am not sure of the proper way to create a EMPTY variable for later use:
Before:
FileStream SourceFile = File.OpenRead(TheFile);
StreamReader sr ; = new StreamReader(SourceFile);
char[] block = new char[3];
byte[] header = new byte[6];
SourceFile.Read(header, 0, 6);
SourceFile.Seek(0, 0);
encoding = (header[1] == 0 && header[3] == 0 && header[5] == 0) ? Encoding.Unicode : Encoding.UTF8;
sr.ReadBlock(block, 0, 3);
String sBlock = new String(block);
SourceFile.Seek(0, 0);
if(sBlock=="ABC")
{
MyFunction(SourceFile);
}
Causes compile errors:
FileStream SourceFile ;
String sBlock ="";
Encoding encoding;
StreamReader sr;
try
{
SourceFile = File.OpenRead(TheFile);
sr = new StreamReader(SourceFile);
char[] block = new char[3];
byte[] header = new byte[6];
SourceFile.Read(header, 0, 6);
SourceFile.Seek(0, 0);
encoding = (header[1] == 0 && header[3] == 0 && header[5] == 0) ? Encoding.Unicode : Encoding.UTF8;
sr.ReadBlock(block, 0, 3);
sBlock = new String(block);
SourceFile.Seek(0, 0);
}
catch (Exception ex)
{
String Error = "Error Accessing: " + TheFile + " System Message: " + ex.Message;
EventLog.LogEvent(dtmLogging.LogEventType.Error, Error);
MessageError(Error, "MyFunction()");
}
if(sBlock=="ABC")
{
MyFunction(SourceFile); //THIS LINE DOES NOT COMPILE: Use of unassigned variables
}
Proposed Change: //If I make this change application appears to work fine, but I am not sure if this is "Proper"
FileStream SourceFile =null;
String sBlock ="";
Encoding encoding = null;
StreamReader sr = null;
Thank you for any help
I would recommend not setting the variable to null in the declaration, at least in a case such as your sample code. In this case, setting it to null actually obscures another problem with the code as written: the catch block allows the method to keep executing (and attempting to use the FileStream object) even though something went wrong and the FileStream object is likely in an unknown state and shouldn't be used.
The reason you were seeing the "red error" initially was because the code could "fall through" the catch block. If you had added a return or throw at the end of the catch block to return control to the caller, the red error would have disappeared and you wouldn't have needed to set the variable to null.
To answer your original question, declaring the variables as you did can be a reasonable way to structure the code. A better way is to incorporate all your actions on the FileStream within the try block so that the variables can be defined and referenced all within that same block. If the try block starts to get too big, it's probably an indication that you should refactor some of its contents out into smaller utility methods that can be called from within the try block.
And one related point: you should have using declarations around objects that need to be closed or otherwise cleaned up after use (i.e. anything that implements the IDisposable interface). This ensures that files get closed and other resources released regardless what happens in the rest of the code.
For example:
try
{
using (FileStream SourceFile = File.OpenRead(TheFile))
using (StreamReader sr = new StreamReader(SourceFile))
{
char[] block = new char[3];
byte[] header = new byte[6];
SourceFile.Read(header, 0, 6);
SourceFile.Seek(0, 0);
Encoding encoding = (header[1] == 0 && header[3] == 0 && header[5] == 0) ? Encoding.Unicode : Encoding.UTF8;
sr.ReadBlock(block, 0, 3);
String sBlock = new String(block);
SourceFile.Seek(0, 0);
if (sBlock=="ABC")
{
MyFunction(SourceFile);
}
// And do anything else you want with SourceFile & sr here
}
}
catch (Exception ex)
{
String Error = "Error Accessing: " + TheFile + " System Message: " + ex.Message;
EventLog.LogEvent(dtmLogging.LogEventType.Error, Error);
MessageError(Error, "MyFunction()");
}
Hope this helps.
SourceFile has been defined in the Try block, it won't be in scope later. It acts as a local variable meant for just Try block.
The below link too will help.
Why aren't variables declared in "try" in scope in "catch" or "finally"?

Categories