Here is an example of what I want to do:
MessageBox.Show("Error line number " + CurrentLineNumber);
In the code above the CurrentLineNumber, should be the line number in the source code of this piece of code.
How can I do that?
In .NET 4.5 / C# 5, you can get the compiler to do this work for you, by writing a utility method that uses the new caller attributes:
using System.Runtime.CompilerServices;
static void SomeMethodSomewhere()
{
ShowMessage("Boo");
}
...
static void ShowMessage(string message,
[CallerLineNumber] int lineNumber = 0,
[CallerMemberName] string caller = null)
{
MessageBox.Show(message + " at line " + lineNumber + " (" + caller + ")");
}
This will display, for example:
Boo at line 39 (SomeMethodSomewhere)
There's also [CallerFilePath] which tells you the path of the original code file.
Use the StackFrame.GetFileLineNumber method, for example:
private static void ReportError(string message)
{
StackFrame callStack = new StackFrame(1, true);
MessageBox.Show("Error: " + message + ", File: " + callStack.GetFileName()
+ ", Line: " + callStack.GetFileLineNumber());
}
See Scott Hanselman's Blog entry for more information.
[Edit: Added the following]
For those using .Net 4.5 or later, consider the CallerFilePath, CallerMethodName and CallerLineNumber attributes in the System.Runtime.CompilerServices namespace. For example:
public void TraceMessage(string message,
[CallerMemberName] string callingMethod = "",
[CallerFilePath] string callingFilePath = "",
[CallerLineNumber] int callingFileLineNumber = 0)
{
// Write out message
}
The arguments must be string for CallerMemberName and CallerFilePath and an int for CallerLineNumber and must have a default value. Specifying these attributes on method parameters instructs the compiler to insert the appropriate value in the calling code at compile time, meaning it works through obfuscation. See Caller Information for more information.
I prefer one liners so:
int lineNumber = (new System.Diagnostics.StackFrame(0, true)).GetFileLineNumber();
In .NET 4.5 you can get the line number by creating the function:
static int LineNumber([System.Runtime.CompilerServices.CallerLineNumber] int lineNumber = 0)
{
return lineNumber;
}
Then each time you call LineNumber() you will have the current line. This has the advantage over any solution using the StackTrace that it should work in both debug and release.
So taking the original request of what is required, it would become:
MessageBox.Show("Error enter code here line number " + LineNumber());
This is building on the excellent answer by Marc Gravell.
For those who need a .NET 4.0+ method solution:
using System;
using System.IO;
using System.Diagnostics;
public static void Log(string message) {
StackFrame stackFrame = new System.Diagnostics.StackTrace(1).GetFrame(1);
string fileName = stackFrame.GetFileName();
string methodName = stackFrame.GetMethod().ToString();
int lineNumber = stackFrame.GetFileLineNumber();
Console.WriteLine("{0}({1}:{2})\n{3}", methodName, Path.GetFileName(fileName), lineNumber, message);
}
How to call:
void Test() {
Log("Look here!");
}
Output:
Void Test()(FILENAME.cs:104)
Look here!
Change the Console.WriteLine format how you like!
If its in a try catch block use this.
try
{
//Do something
}
catch (Exception ex)
{
System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace(ex, true);
Console.WriteLine("Line: " + trace.GetFrame(0).GetFileLineNumber());
}
You only asked about the line number and with nullable project type, you then need to use a something like this
internal class Utils
{
public static int Line([CallerLineNumber] int? lineNumber =null)=>lineNumber;
}
in your code, if you like to get a line number you then just call
var line=Utils.Line();
if you are logging and you would like to document the line number in say logging than call the method like this
public void MyMethod(int someValue)
{
switch(someValue)
{
case 1:
if(abc<xyz)
{
logger.LogInformation("case value {someValue} this line {line} was true", someValue ,Utils.Line()-2);
}
break;
case 2:
logger.LogInformation("case value {someValue} this {line} was executed",someValue,Utils.Line());
break;
caste 3:
logger.LogInformation("case value {someValue} this {line} was executed",someValue,Utils.Line());
break;
}
}
You can extend this pattern with any of the other [CallerXXX] methods and not use them where ever, not just in the method parameters.
in the Nuget Package Walter I use a super cool class named ExceptionObject
if you import the NuGet package you have some nice extension methods on the Exception class as well as access to a CallStack showing the call chain including method parameters and parameter values of all methods called.
It's like a stack of an exception only with values showing how you got where you got with what values.
public void MyMethod()
{
try
{
//get me all methods, signatures, parameters line numbers file names etc used as well as assembly info of all assemblies used for documentation of how the code got here
var stack= new CallStack();
foreach( var frame in StackedFrames)
{
logger.LogDebug(frame.ToString());
}
}
catch(SqlException e)
{
var ex = new ExceptionObject(e);
logger.LogException(e,"{this} exception due to {message} {server} {procedure} TSQL-line:{sqlline}\n{TSQL}"
,e.GetType().Name
,e.Message
,ex.SqlServer
,ex.SqlProcedureName
,ex.SqlLineNumber
,ex.Tsql
,ex.CallStack);
}
catch(Exception e)
{
var ex = new ExceptionObject(e);
logger.LogException(e,"{this} exception due to {message} signature: signature}\nCallStack:", e.GetType().Name,e.Message,ex.Signature,ex.CallStack);
}
}
Related
So i'm making a basic 2D platformer in Unity, I want to be able to save the time it takes the player to complete each level and display the fastest time in a UI element. I'm writing the times to a text file (this works fine), and reading all the times line by line into a list, from there I find the lowest value etc. However, my code does not work, it gives me the following error when I'm calling the function from another script. I'm new to C# so would greatly appreciate any help anyone can give me!
Thanks!
Full Error Message
InvalidOperationException: Operation is not valid due to the current state of the object
System.Linq.Enumerable.Iterate[Single,Single] (IEnumerable1 source, Single initValue, System.Func3 selector)
System.Linq.Enumerable.Min (IEnumerable`1 source)
SaveScores.ReadData (System.String LevelLoaded) (at Assets/Scripts/Highscores/SaveScores.cs:73)
GameManager.Update () (at Assets/Scripts/GameManager.cs:45)
Code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using System;
using System.Linq;
public class SaveScores : MonoBehaviour {
void Start()
{
//ReadData();
}
public static void WriteData(float time, string LevelLoaded)
{
try
{
//Debug.Log("Saving time");
StreamWriter sw = new StreamWriter(#"C:\Users\Theo\Documents\Unity Projects\V13\Platformer\Assets\Scripts\Highscores\Scores.txt", true);
sw.WriteLine(LevelLoaded + " " + time);
sw.Close();
}
catch(Exception e)
{
Console.WriteLine("Exception: " + e.Message);
}
finally
{
Console.WriteLine("Executing final block");
}
}
public static void ReadData(string LevelLoaded)
{
List <float> timesLevel1 = new List<float>();
List <float> timesLevel2 = new List<float>();
List <float> timesLevel3 = new List<float>();
try
{
var lines = File.ReadAllLines(#"C:\Users\Theo\Documents\Unity Projects\V13\Platformer\Assets\Scripts\Highscores\Scores.txt");
foreach (var line in lines)
{
if (line.Contains("Level1"))
{
timesLevel1.Add(Convert.ToSingle(line));
}
else if (line.Contains("Level2"))
{
timesLevel2.Add(Convert.ToSingle(line));
}
else if (line.Contains("Level3"))
{
timesLevel3.Add(Convert.ToSingle(line));
}
}
}
catch (Exception e)
{
Console.WriteLine("Exception: " + e.Message);
}
finally
{
Console.WriteLine("Executing final block");
}
switch (LevelLoaded)
{
case "Level1":
UIManager.lowestTime = timesLevel1.Min();
break;
case "Level2":
UIManager.lowestTime = timesLevel2.Min();
break;
case "Level3":
UIManager.lowestTime = timesLevel3.Min();
break;
}
}
}
If you look at the documentation for Enumerable.Min<float> (https://msdn.microsoft.com/en-us/library/bb361144(v=vs.110).aspx) you will see that under "Exceptions" it lists the InvalidOperationException and gives the reason as: "source contains no elements".
What this likely means is that the list you are looking at doesn't contain any elements.
On looking at what is populating that list there seems to be some confusion in what you expect to be in the line. You do a test for line.Contains("Level1") but if that succeeds then you call Convert.ToSingle(line) which would fail if there was any string data in that line (eg if line did contain that string then the convert would fail).
So it seems likely that the format of the file you are reading is not what you expect it to be leading to your lists being empty leading to this error.
We are currently working on a logging solution and have implemented an extension method call 'Log'. When writing to the log file, we would ideally like to write the original variable name (rather than the variable name used in the extension method).
What we are currently having to do for this is:
public void DoSomeWork()
{
String testString = "Hey look I'm a string!";
testString.Log("testString value");
}
With the extention method:
public static String Log(this String valueToStore, String name)
{
// The logging code which uses the 'name' parameter
}
The issue here is that it becomes difficult to read on longer lines of code and looks clustered. What would be ideal is this:
public void DoSomeWork()
{
String testString = "Hey look I'm a string!";
testString.Log();
}
With the extension method:
public static String Log(this String valueToStore)
{
// The logging code which is able to retrieve the
// value 'testString' from the 'valueToStore' value
}
Is this at all possible by using Reflection? I'm aware of the nameofoption, but that only returns the string 'valueToStore' when used in the extension method.
Well, short answer is no. The variable names are not guaranteed to persist after compilation in unchanged form. That information would have to be somehow persisted (for example by the use of nameof()). Also, the variable name might not exist ("test".GetVarName()).
The long answer is: yes, possibly, but it's one of the most ridiculous things I've created in my life:
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
namespace Test1
{
class Program
{
static void Main(string[] args)
{
var myVarName = "test";
myVarName.Test();
Console.ReadKey();
}
}
static class Extensions
{
public static void Test(
this string str,
[System.Runtime.CompilerServices.CallerMemberName] string memberName = "",
[System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "",
[System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0
)
{
var relevantLine = File.ReadAllLines(sourceFilePath)[sourceLineNumber-1];
var currMethodName = MethodInfo.GetCurrentMethod().Name;
var callIndex = relevantLine.IndexOf(currMethodName + "()");
var sb = new Stack<char>();
for (var i = callIndex - 2; i >= 0; --i)
{
if (Char.IsLetterOrDigit(relevantLine[i]))
{
sb.Push(relevantLine[i]);
}
}
Console.WriteLine(new String(sb.ToArray()));
}
}
}
C# 10 has CallerArgumentExpressionAttribute that will do just that
public static void PrintNameAndValue(
this object obj,
[System.Runtime.CompilerServices.CallerArgumentExpression("obj")] string callerExp = ""
)
{
Console.WriteLine(callerExp + " = " + obj.ToString());
}
It'll capture the entire expression passed:
public void TestPrintNameAndValue()
{
string mystring = "test";
int myint = 5;
mystring.PrintNameAndValue(); // mystring = test
myint.PrintNameAndValue(); // myint = 5
(myint + 10).PrintNameAndValue(); // myint + 10 = 15
mystring.ToUpper().PrintNameAndValue(); // mystring.ToUpper() = TEST
}
You can use an Expression to achieve that, but performance-wise it may not be the best option:
public static void Log<T>(Expression<Func<T>> expr)
{
var memberExpr = expr.Body as MemberExpression;
if (memberExpr == null)
return;
var varName = memberExpr.Member.Name;
var varData = expr.Compile()();
// actual logging
...
}
Usage:
var test = "Foo";
Log(() => test);
Alternatively, if you're using C# 6.0, it can get a bit better using the nameof operator:
test.Log(nameof(test));
A better solution would be one that is leveraging the compiler abilities (specifically, the "Roslyn" compiler) and provide the member name on compile time.
Not really an answer, more of a pointer, but you could try doing something with your application that you're using(e.g. visual studio) instead of doing it in code. What I mean is make it rewrite everything that looks like [variable].Log(); to [variable].Log([variable])
I am pretty sure that there has to be some weird macro or plugin which does this for you before compiling.
I often want to do this:
public void Foo(Bar arg)
{
throw new ArgumentException("Argument is incompatible with " + name(Foo));
}
Because if I change the name of Foo the IDE will refactor my error message too, what won't happen if I put the name of the method (or any other kind of member identifier) inside a string literal. The only way I know of implementing "name" is by using reflection, but I think the performance loss outweighs the mantainability gain and it won't cover all kinds of identifiers.
The value of the expression between parenthesis could be computed at compile time (like typeof) and optimized to become one string literal by changing the language specification. Do you think this is a worthy feature?
PS: The first example made it look like the question is related only to exceptions, but it is not. Think of every situation you may want to reference a type member identifier. You'll have to do it through a string literal, right?
Another example:
[RuntimeAcessibleDocumentation(Description="The class " + name(Baz) +
" does its job. See method " + name(DoItsJob) + " for more info.")]
public class Baz
{
[RuntimeAcessibleDocumentation(Description="This method will just pretend " +
"doing its job if the argument " + name(DoItsJob.Arguments.justPretend) +
" is true.")]
public void DoItsJob(bool justPretend)
{
if (justPretend)
Logger.log(name(justPretend) + "was true. Nothing done.");
}
}
UPDATE: this question was posted before C# 6, but may still be relevant for those who are using previous versions of the language. If you are using C# 6 check out the nameof operator, which does pretty much the same thing as the name operator in the examples above.
well, you could cheat and use something like:
public static string CallerName([CallerMemberName]string callerName = null)
{
return callerName;
}
and:
public void Foo(Bar arg)
{
throw new ArgumentException("Argument is incompatible with " + CallerName());
}
Here, all the work is done by the compiler (at compile-time), so if you rename the method it will immediately return the correct thing.
If you simply want the current method name: MethodBase.GetCurrentMethod().Name
If it's a type typeof(Foo).Name
If you want the name of a variable/parameter/field/property, with a little Expression tree
public static string GetFieldName<T>(Expression<Func<T>> exp)
{
var body = exp.Body as MemberExpression;
if (body == null)
{
throw new ArgumentException();
}
return body.Member.Name;
}
string str = "Hello World";
string variableName = GetFieldName(() => str);
For method names it's a little more tricky:
public static readonly MethodInfo CreateDelegate = typeof(Delegate).GetMethod("CreateDelegate", BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(Type), typeof(object), typeof(MethodInfo) }, null);
public static string GetMethodName<T>(Expression<Func<T>> exp)
{
var body = exp.Body as UnaryExpression;
if (body == null || body.NodeType != ExpressionType.Convert)
{
throw new ArgumentException();
}
var call = body.Operand as MethodCallExpression;
if (call == null)
{
throw new ArgumentException();
}
if (call.Method != CreateDelegate)
{
throw new ArgumentException();
}
var method = call.Arguments[2] as ConstantExpression;
if (method == null)
{
throw new ArgumentException();
}
MethodInfo method2 = (MethodInfo)method.Value;
return method2.Name;
}
and when you call them you have to specify the type of a compatible delegate (Action, Action<...>, Func<...> ...)
string str5 = GetMethodName<Action>(() => Main);
string str6 = GetMethodName<Func<int>>(() => Method1);
string str7 = GetMethodName<Func<int, int>>(() => Method2);
or more simply, without using expressions :-)
public static string GetMethodName(Delegate del)
{
return del.Method.Name;
}
string str8 = GetMethodName((Action)Main);
string str9 = GetMethodName((Func<int>)Method1);
string str10 = GetMethodName((Func<int, int>)Method2);
As has been covered, using this approach for exceptions seems unnecessary due to the method name being in the call stack on the exception.
In relation to the other example in the question of logging the parameter value, it seems PostSharp would be a good candidate here, and probably would allow lots of new features of this kind that you're interested in.
Have a look at this page on PostSharp which came up when I searched for how to use PostSharp to log parameter values (which it covers). An excerpt taken from that page:
You can get a lot of useful information with an aspect, but there are three popular categories:
Code information: function name, class name, parameter values, etc. This can help you to reduce guessing in pinning down logic flaws or edge-case scenarios
Performance information: keep track of how much time a method is taking
Exceptions: catch select/all exceptions and log information about them
The original question is named "How to refer to an identifier without writing it into a string literal in C#?" This answer does not answer that question, instead, it answers the question "How to refer to an identifier by writing its name into a string literal using a preprocessor?"
Here is a very simple "proof of concept" C# preprocessor program:
using System;
using System.IO;
namespace StackOverflowPreprocessor
{
/// <summary>
/// This is a C# preprocessor program to demonstrate how you can use a preprocessor to modify the
/// C# source code in a program so it gets self-referential strings placed in it.
/// </summary>
public class PreprocessorProgram
{
/// <summary>
/// The Main() method is where it all starts, of course.
/// </summary>
/// <param name="args">must be one argument, the full name of the .csproj file</param>
/// <returns>0 = OK, 1 = error (error message has been written to console)</returns>
static int Main(string[] args)
{
try
{
// Check the argument
if (args.Length != 1)
{
DisplayError("There must be exactly one argument.");
return 1;
}
// Check the .csproj file exists
if (!File.Exists(args[0]))
{
DisplayError("File '" + args[0] + "' does not exist.");
return 1;
}
// Loop to process each C# source file in same folder as .csproj file. Alternative
// technique (used in my real preprocessor program) is to read the .csproj file as an
// XML document and process the <Compile> elements.
DirectoryInfo directoryInfo = new DirectoryInfo(Path.GetDirectoryName(args[0]));
foreach (FileInfo fileInfo in directoryInfo.GetFiles("*.cs"))
{
if (!ProcessOneFile(fileInfo.FullName))
return 1;
}
}
catch (Exception e)
{
DisplayError("Exception while processing .csproj file '" + args[0] + "'.", e);
return 1;
}
Console.WriteLine("Preprocessor normal completion.");
return 0; // All OK
}
/// <summary>
/// Method to do very simple preprocessing of a single C# source file. This is just "proof of
/// concept" - in my real preprocessor program I use regex and test for many different things
/// that I recognize and process in one way or another.
/// </summary>
private static bool ProcessOneFile(string fileName)
{
bool fileModified = false;
string lastMethodName = "*unknown*";
int i = -1, j = -1;
try
{
string[] sourceLines = File.ReadAllLines(fileName);
for (int lineNumber = 0; lineNumber < sourceLines.Length - 1; lineNumber++)
{
string sourceLine = sourceLines[lineNumber];
if (sourceLine.Trim() == "//?GrabMethodName")
{
string nextLine = sourceLines[++lineNumber];
j = nextLine.IndexOf('(');
if (j != -1)
i = nextLine.LastIndexOf(' ', j);
if (j != -1 && i != -1 && i < j)
lastMethodName = nextLine.Substring(i + 1, j - i - 1);
else
{
DisplayError("Unable to find method name in line " + (lineNumber + 1) +
" of file '" + fileName + "'.");
return false;
}
}
else if (sourceLine.Trim() == "//?DumpNameInStringAssignment")
{
string nextLine = sourceLines[++lineNumber];
i = nextLine.IndexOf('\"');
if (i != -1 && i != nextLine.Length - 1)
{
j = nextLine.LastIndexOf('\"');
if (i != j)
{
sourceLines[lineNumber] =
nextLine.Remove(i + 1) + lastMethodName + nextLine.Substring(j);
fileModified = true;
}
}
}
}
if (fileModified)
File.WriteAllLines(fileName, sourceLines);
}
catch (Exception e)
{
DisplayError("Exception while processing C# file '" + fileName + "'.", e);
return false;
}
return true;
}
/// <summary>
/// Method to display an error message on the console.
/// </summary>
private static void DisplayError(string errorText)
{
Console.WriteLine("Preprocessor: " + errorText);
}
/// <summary>
/// Method to display an error message on the console.
/// </summary>
internal static void DisplayError(string errorText, Exception exceptionObject)
{
Console.WriteLine("Preprocessor: " + errorText + " - " + exceptionObject.Message);
}
}
}
And here's a test file, based on the first half of the original question:
using System;
namespace StackOverflowDemo
{
public class DemoProgram
{
public class Bar
{}
static void Main(string[] args)
{}
//?GrabMethodName
public void Foo(Bar arg)
{
//?DumpNameInStringAssignment
string methodName = "??"; // Will be changed as necessary by preprocessor
throw new ArgumentException("Argument is incompatible with " + methodName);
}
}
}
To make the running of the preprocessor program a part of the build process you modify the .csproj file in two places. Insert this line in the first section:
<UseHostCompilerIfAvailable>false</UseHostCompilerIfAvailable>
(This is optional - see here https://stackoverflow.com/a/12163384/253938 for more information.)
And at the end of the .csproj file replace some lines that are commented-out with these lines:
<Target Name="BeforeBuild">
<Exec WorkingDirectory="D:\Merlinia\Trunk-Debug\Common\Build Tools\Merlinia Preprocessor\VS2012 projects\StackOverflowPreprocessor\bin" Command="StackOverflowPreprocessor.exe "$(MSBuildProjectFullPath)"" />
</Target>
Now when you recompile the test program the line that says
string methodName = "??"; // Will be changed as necessary by preprocessor
will be magically converted to say
string methodName = "Foo"; // Will be changed as necessary by preprocessor
OK?
Version 6 of C# has introduced the nameof operator which works like the name operator described in the examples of the question, but with some restrictions. Here are some examples and excerpts from the C# FAQ blog:
(if x == null) throw new ArgumentNullException(nameof(x));
You can put more elaborate dotted names in a nameof expression, but that’s just to tell the compiler where to look: only the final identifier will be used:
WriteLine(nameof(person.Address.ZipCode)); // prints "ZipCode"
Note: there are small design changes to nameof since the Preview was built. In the preview, dotted expressions like in the last example, where person is a variable in scope, are not allowed. Instead you have to dot in through the type.
My code:
public class CLASS_A {
public static Dictionary<int, CLASS_A> List = new Dictionary<int, CLASS_A>;
public static PP_CLASS pp = null;
public static CLASS_A ID
{
get
{
int key = get_threadID;
if (List.ContainsKey(key))
return List[key];
else
return null;
}
set
{
int key = get_threadID;
List[key] = value;
}
}
public virtual void init(lib, name)
{
...
if (name != "")
{
if (pp == null)
PP = this;
}
...
}
}
So whichever thread calls init, it's id is used to store this (whoever called). Eg my list looks like this:
45 = CLASS_A_object0
67 = CLASS_A_object1
...
But now when a different thread calls a method on pp, say CLASS_A.pp.setWelcome, this will return null for pp, and throws null exception! Because when set is called the thread id will be different and won't be in the list.
So is it possible that I know which object called so that I can do reverse lookup? Or maybe a different solution?
Why I want this:
Initially we were connecting to one device so that was ok. Now there are multiple devices with each one having its own ip/port. Initial code had just public static PP_CLASS pp = null; So others will be just calling methods on pp using class name and things were good.
Previous behaviour: The software picks list of devices from a file and since pp is static it only talks to the first device. I added that pp==null line which i forgot in my initial post. So when the code starts pp==null will be true and first device is assigned, but now for other devices pp==null will be false and thus I am not able to talk to other devices.
Please let me know if more details are needed.
Beginning with C# 5.0 (August 2012) there is a new feature "Caller Info Attribute". If your classes are stored in separate files, you can make use of the CallerFilePathAttribute to register which class actually has called.
Example from MSDN:
// using System.Runtime.CompilerServices
// using System.Diagnostics;
public void DoProcessing()
{
TraceMessage("Something happened.");
}
public void TraceMessage(string message,
[CallerMemberName] string memberName = "",
[CallerFilePath] string sourceFilePath = "",
[CallerLineNumber] int sourceLineNumber = 0)
{
Trace.WriteLine("message: " + message);
Trace.WriteLine("member name: " + memberName);
Trace.WriteLine("source file path: " + sourceFilePath);
Trace.WriteLine("source line number: " + sourceLineNumber);
}
// Sample Output:
// message: Something happened.
// member name: DoProcessing
// source file path: c:\Users\username\Documents\Visual Studio 2012\Projects\CallerInfoCS\CallerInfoCS\Form1.cs
// source line number: 31
You could try examining the Stack Trace.
var trace = new System.Diagnostics.StackTrace();
or to get the calling line only it should be something like:
var caller = new System.Diagnostics.StackTrace().GetFrame(1)
I am trying to create a program to copy all the files from one directory to another. But I am running in a basic issue. It says indentifier expected when I try to compile on line 52.
public bool RecursiveCopy()
{
string origDir = #"D:\Documents and Settings\Dub\My Documents\HoN Updates\test";
string destDir = #"C:\Games\HoN";
bool status = false;
//get all the info about the original directory
var dirInfo = new DirectoryInfo(origDir);
//retrieve all the _fileNames in the original directory
var files = dirInfo.GetFiles(origDir);
//always use a try...catch to deal
//with any exceptions that may occur
try
{
//loop through all the file names and copy them
foreach (string file in Directory.GetFiles(origDir))
{
var origFile = new FileInfo(file);
var destFile = new FileInfo(file.Replace(origDir, destDir));
//copy the file, use the OverWrite overload to overwrite
//destination file if it exists
System.IO.File.Copy(origFile.FullName, destFile.FullName, true);
//TODO: If you dont want to remove the original
//_fileNames comment this line out
File.Delete(origFile.FullName);
status = true;
}
Console.WriteLine("All files in " + origDir + " copied successfully!");
}
catch (Exception ex)
{
status = false;
//handle any errors that may have occurred
Console.WriteLine(ex.Message);
}
return status;
}
public string origDir = #"D:\Documents and Settings\Dub\My Documents\HoN Updates\test"; // ERROR HERE
public string destDir = #"C:\Games\HoN"; // ERROR HERE
private static void RecursiveCopy(origDir, destDir)
{
Console.WriteLine("done");
Console.ReadLine();
}
You did not give type identifiers to your argument list here
static void RecursiveCopy(origDir, destDir)
should be
static void RecursiveCopy(string origDir, string destDir)
Your method RecursiveCopy has two parameters listed without their types. It should be this:
static void RecursiveCopy(string origDir, string destDir)
Here is your problem:
static void RecursiveCopy(origDir, destDir)
You don't specify the types for the parameters, perhaps you intended the following:
static void RecursiveCopy(string origDir, string destDir)
There are more issues however that I've noticed. It's possible you're still working on these, but from what you've posted:
You never call your RecursiveCopy method. Perhaps you meant to call it from Main() instead of declaring an overload with two parameters?
You declare two public fields origDir and destDir but then never use them. Instead you create two local variables in RecursiveCopy() and use these instead. Did you intend to create parameters or use the public fields instead?
Your copy is not actually true to its name of "recursive".
cYou are missing the parameter types in the RecursiveCopy method declaration. Just Change
static void RecursiveCopy(origDir, destDir)
to
static void RecursiveCopy(String origDir, String destDir)
and all is fine.