Loosing an XML file when using XmlSerializer - c#

Sometimes, when I save to XML, I end up with a completely empty XML file.
I can't reproduce the issue on demand yet. It is just occasional. Are there steps that one can take to assist the user in this regard?
At the moment I do this:
public bool SavePublisherData()
{
bool bSaved = false;
try
{
XmlSerializer x = new XmlSerializer(_PublisherData.GetType());
using (StreamWriter writer = new StreamWriter(_strPathXML))
{
_PublisherData.BuildPublisherListFromDictionary();
x.Serialize(writer, _PublisherData);
bSaved = true;
}
}
catch
{
}
return bSaved;
}
The reason I have not put anything in the catch block is because this code is part of a C# DLL and I am calling it from an MFC project. I have read that you can't (or shouldn't) pass exceptions through from one environment to another. Thus, when an exception happens in my DLL I don't really know how I can sensibly feed that information to the user so they can see it. That is a side issue.
But this is how I save it. So, what steps can one take to try and prevent complete data loss?
Thank you.
Update
I have looked at the KB article that the link in the comments refers to and it states:
Use the following XmlSerializer class constructors. These class constructors cache the assemblies.
This is also re-stated in the article itself indicated in the comments:
What is the solution?
The default constructors XmlSerializer(type) and XmlSerializer(type, defaultNameSpace) caches the dynamic assembly so if you use those constructors only one copy of the dynamic assembly needs to be created.
Seems pretty smart… why not do this in all constructors? Hmm… interesting idea, wonder why they didn’t think of that one:) Ok, the other constructors are used for special cases, and the assumption would be that you wouldn’t create a ton of the same XmlSerializers using those special cases, which would mean that we would cache a lot of items we later didn’t need and use up a lot of extra space. Sometimes you have to do what is good for the majority of the people.
So what do you do if you need to use one of the other constructors? My suggestion would be to cache the XmlSerializer if you need to use it often. Then it would only be created once.
My code uses one of these default constructors as you can see:
XmlSerializer(_PublisherData.GetType());
So I don't think I need to worry about this XmlSerializerFactory in this instance.

Related

Tell FxCop another method is calling dispose

Typically when you dispose a private member, you might do the following:
public void Dispose() {
var localInst = this.privateMember;
if (localInst != null) {
localInst.Dispose();
}
}
The purpose of the local assignment is to avoid a race condition where another thread might assign the private member to be null after the null check. In this case, I don't care if Dispose is called twice on the instance.
I use this pattern all the time so I wrote an extension method to do this:
public static void SafeDispose(this IDisposable disposable)
{
if (disposable != null)
{
// We also know disposable cannot be null here,
// even if the original reference is null.
disposable.Dispose();
}
}
And now in my class, I can just do this:
public void Dispose() {
this.privateMember.SafeDispose();
}
Problem is, FxCop has no idea I'm doing this and it gives me the CA2000: Dispose objects before losing scope warning in every case.
I don't want to turn off this rule and I don't want to suppress every case. Is there a way to hint to FxCop that this method is equivalent to Dispose as far as it's concerned?
The short answer is: there's no way to hint that the object is being disposed elsewhere.
A little bit of Reflector-ing (or dotPeek-ing, or whatever) explains why.
FxCop is in C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop. (Adjust accordingly for your OS/VS version combo.) Rules are in the Rules subdirectory.
In the main FxCop folder, open
Microsoft.VisualStudio.CodeAnalysis.dll
Microsoft.VisualStudio.CodeAnalysis.Phoenix.dll
phx.dll
In the Rules folder, open DataflowRules.dll.
In DataflowRules.dll find Phoenix.CodeAnalysis.DataflowRules.DisposeObjectsBeforeLosingScope. That's the actual class that does the evaluation.
Looking at the code in there, you can see two things of interest with respect to your question.
It uses a shared service called SharedNeedsDisposedAnalysis.
It derives from FunctionBodyRule.
The first item is interesting because SharedNeedsDisposedAnalysis is what determines which symbols need Dispose() called. It's pretty thorough, doing a "walk" through the code to determine what needs to be disposed and what actually gets disposed. It then keeps a table of those things for later use.
The second item is interesting because FunctionBodyRule rules evaluate the body of a single function. There are other rule types, like FunctionCallRule that evaluate things like function call members (e.g., ProvideCorrectArgumentsToFormattingMethods).
The point is, between the potential "miss" in that SharedNeedsDisposedAnalysis service where it may not be recursing through your method to see that things actually are getting disposed and the limitation of FunctionBodyRule not going beyond the function body, it's just not catching your extension.
This is the same reason "guard functions" like Guard.Against<ArgumentNullException>(arg) never get seen as validating the argument before you use it - FxCop will still tell you to check the argument for null even though that's what the "guard function" is doing.
You have basically two options.
Exclude issues or turn off the rule. There's no way it's going to do what you want.
Create a custom/derived rule that will understand extension methods. Use your custom rule in place of the default rule.
After having written custom FxCop rules myself, I'll let you know I found it... non-trivial. If you do go down that road, while the recommendation out in the world is to use the new Phoenix engine rule style (that's what the current DisposeObjectsBeforeLosingScope uses), I found it easier to understand the older/standard FxCop SDK rules (see FxCopSdk.dll in the main FxCop folder). Reflector will be a huge help in figuring out how to do that since there's pretty much zero doc on it. Look in the other assemblies in the Rules folder to see examples of those.
I am by no means an FxCop expert at all, but does this question about using SuppressMessage answer it? I don't know if decorating your SafeDispose method with the SuppressMessage attribute would cause FxCop to suppress that message on its analysis of the methods that call it, but seems like it's worth a shot.
Don't trust the syntax below, but something like:
[SuppressMessage("Microsoft.Design", "CA2000:Dispose objects before losing scope", Justification = "We just log the exception and return an HTTP code")]
public static void SafeDispose(this IDisposable disposable)
This code analysis rule is a problematic one, for all the reasons Travis outlined. It seems to queue off any "new" operation, and unless the dispose call is close, CA2000 triggers.
Instead of using new, call a method with this in the body:
MyDisposableClass result;
MyDisposableClass temp = null;
try
{
temp = new MyDisposableClass();
//do any initialization here
result = temp;
temp = null;
}
finally
{
if (temp != null) temp.Dispose();
}
return result;
What this does is remove any possibility of the initialization causing the object to be unreachable for disposal. In your case, when you "new up" privatemember, you would do it within a method that looks like the above method. After using this pattern, you are of course still responsible for correct disposal, and your extension method is a great way to generalize that null check.
I've found that you can avoid CA2000 while still passing IDisposables around and doing what you want with them - as long as you new them up correctly within a method like the above. Give it a try and let me know if it works for you. Good luck, and good question!
Other fixes for this rule (including this one) are outlined here: CA2000: Dispose objects before losing scope (Microsoft)

How to enforce the use of a method's return value in C#?

I have a piece of software written with fluent syntax. The method chain has a definitive "ending", before which nothing useful is actually done in the code (think NBuilder, or Linq-to-SQL's query generation not actually hitting the database until we iterate over our objects with, say, ToList()).
The problem I am having is there is confusion among other developers about proper usage of the code. They are neglecting to call the "ending" method (thus never actually "doing anything")!
I am interested in enforcing the usage of the return value of some of my methods so that we can never "end the chain" without calling that "Finalize()" or "Save()" method that actually does the work.
Consider the following code:
//The "factory" class the user will be dealing with
public class FluentClass
{
//The entry point for this software
public IntermediateClass<T> Init<T>()
{
return new IntermediateClass<T>();
}
}
//The class that actually does the work
public class IntermediateClass<T>
{
private List<T> _values;
//The user cannot call this constructor
internal IntermediateClass<T>()
{
_values = new List<T>();
}
//Once generated, they can call "setup" methods such as this
public IntermediateClass<T> With(T value)
{
var instance = new IntermediateClass<T>() { _values = _values };
instance._values.Add(value);
return instance;
}
//Picture "lazy loading" - you have to call this method to
//actually do anything worthwhile
public void Save()
{
var itemCount = _values.Count();
. . . //save to database, write a log, do some real work
}
}
As you can see, proper usage of this code would be something like:
new FluentClass().Init<int>().With(-1).With(300).With(42).Save();
The problem is that people are using it this way (thinking it achieves the same as the above):
new FluentClass().Init<int>().With(-1).With(300).With(42);
So pervasive is this problem that, with entirely good intentions, another developer once actually changed the name of the "Init" method to indicate that THAT method was doing the "real work" of the software.
Logic errors like these are very difficult to spot, and, of course, it compiles, because it is perfectly acceptable to call a method with a return value and just "pretend" it returns void. Visual Studio doesn't care if you do this; your software will still compile and run (although in some cases I believe it throws a warning). This is a great feature to have, of course. Imagine a simple "InsertToDatabase" method that returns the ID of the new row as an integer - it is easy to see that there are some cases where we need that ID, and some cases where we could do without it.
In the case of this piece of software, there is definitively never any reason to eschew that "Save" function at the end of the method chain. It is a very specialized utility, and the only gain comes from the final step.
I want somebody's software to fail at the compiler level if they call "With()" and not "Save()".
It seems like an impossible task by traditional means - but that's why I come to you guys. Is there an Attribute I can use to prevent a method from being "cast to void" or some such?
Note: The alternate way of achieving this goal that has already been suggested to me is writing a suite of unit tests to enforce this rule, and using something like http://www.testdriven.net to bind them to the compiler. This is an acceptable solution, but I am hoping for something more elegant.
I don't know of a way to enforce this at a compiler level. It's often requested for objects which implement IDisposable as well, but isn't really enforceable.
One potential option which can help, however, is to set up your class, in DEBUG only, to have a finalizer that logs/throws/etc. if Save() was never called. This can help you discover these runtime problems while debugging instead of relying on searching the code, etc.
However, make sure that, in release mode, this is not used, as it will incur a performance overhead since the addition of an unnecessary finalizer is very bad on GC performance.
You could require specific methods to use a callback like so:
new FluentClass().Init<int>(x =>
{
x.Save(y =>
{
y.With(-1),
y.With(300)
});
});
The with method returns some specific object, and the only way to get that object is by calling x.Save(), which itself has a callback that lets you set up your indeterminate number of with statements. So the init takes something like this:
public T Init<T>(Func<MyInitInputType, MySaveResultType> initSetup)
I can think of three a few solutions, not ideal.
AIUI what you want is a function which is called when the temporary variable goes out of scope (as in, when it becomes available for garbage collection, but will probably not be garbage collected for some time yet). (See: The difference between a destructor and a finalizer?) This hypothetical function would say "if you've constructed a query in this object but not called save, produce an error". C++/CLI calls this RAII, and in C++/CLI there is a concept of a "destructor" when the object isn't used any more, and a "finaliser" which is called when it's finally garbage collected. Very confusingly, C# has only a so-called destructor, but this is only called by the garbage collector (it would be valid for the framework to call it earlier, as if it were partially cleaning the object immediately, but AFAIK it doesn't do anything like that). So what you would like is a C++/CLI destructor. Unfortunately, AIUI this maps onto the concept of IDisposable, which exposes a dispose() method which can be called when a C++/CLI destructor would be called, or when the C# destructor is called -- but AIUI you still have to call "dispose" manually, which defeats the point?
Refactor the interface slightly to convey the concept more accurately. Call the init function something like "prepareQuery" or "AAA" or "initRememberToCallSaveOrThisWontDoAnything". (The last is an exaggeration, but it might be necessary to make the point).
This is more of a social problem than a technical problem. The interface should make it easy to do the right thing, but programmers do have to know how to use code! Get all the programmers together. Explain simply once-and-for-all this simple fact. If necessary have them all sign a piece of paper saying they understand, and if they wilfully continue to write code which doesn't do anythign they're worse than useless to the company and will be fired.
Fiddle with the way the operators are chained, eg. have each of the intermediateClass functions assemble an aggregate intermediateclass object containing all of the parameters (you mostly do it this was already (?)) but require an init-like function of the original class to take that as an argument, rather than have them chained after it, and then you can have save and the other functions return two different class types (with essentially the same contents), and have init only accept a class of the correct type.
The fact that it's still a problem suggests that either your coworkers need a helpful reminder, or they're rather sub-par, or the interface wasn't very clear (perhaps its perfectly good, but the author didn't realise it wouldn't be clear if you only used it in passing rather than getting to know it), or you yourself have misunderstood the situation. A technical solution would be good, but you should probably think about why the problem occurred and how to communicate more clearly, probably asking someone senior's input.
After great deliberation and trial and error, it turns out that throwing an exception from the Finalize() method was not going to work for me. Apparently, you simply can't do that; the exception gets eaten up, because garbage collection operates non-deterministically. I was unable to get the software to call Dispose() automatically from the destructor either. Jack V.'s comment explains this well; here was the link he posted, for redundancy/emphasis:
The difference between a destructor and a finalizer?
Changing the syntax to use a callback was a clever way to make the behavior foolproof, but the agreed-upon syntax was fixed, and I had to work with it. Our company is all about fluent method chains. I was also a fan of the "out parameter" solution to be honest, but again, the bottom line is the method signatures simply could not change.
Helpful information about my particular problem includes the fact that my software is only ever to be run as part of a suite of unit tests - so efficiency is not a problem.
What I ended up doing was use Mono.Cecil to Reflect upon the Calling Assembly (the code calling into my software). Note that System.Reflection was insufficient for my purposes, because it cannot pinpoint method references, but I still needed(?) to use it to get the "calling assembly" itself (Mono.Cecil remains underdocumented, so it's possible I just need to get more familiar with it in order to do away with System.Reflection altogether; that remains to be seen....)
I placed the Mono.Cecil code in the Init() method, and the structure now looks something like:
public IntermediateClass<T> Init<T>()
{
ValidateUsage(Assembly.GetCallingAssembly());
return new IntermediateClass<T>();
}
void ValidateUsage(Assembly assembly)
{
// 1) Use Mono.Cecil to inspect the codebase inside the assembly
var assemblyLocation = assembly.CodeBase.Replace("file:///", "");
var monoCecilAssembly = AssemblyFactory.GetAssembly(assemblyLocation);
// 2) Retrieve the list of Instructions in the calling method
var methods = monoCecilAssembly.Modules...Types...Methods...Instructions
// (It's a little more complicated than that...
// if anybody would like more specific information on how I got this,
// let me know... I just didn't want to clutter up this post)
// 3) Those instructions refer to OpCodes and Operands....
// Defining "invalid method" as a method that calls "Init" but not "Save"
var methodCallingInit = method.Body.Instructions.Any
(instruction => instruction.OpCode.Name.Equals("callvirt")
&& instruction.Operand is IMethodReference
&& instruction.Operand.ToString.Equals(INITMETHODSIGNATURE);
var methodNotCallingSave = !method.Body.Instructions.Any
(instruction => instruction.OpCode.Name.Equals("callvirt")
&& instruction.Operand is IMethodReference
&& instruction.Operand.ToString.Equals(SAVEMETHODSIGNATURE);
var methodInvalid = methodCallingInit && methodNotCallingSave;
// Note: this is partially pseudocode;
// It doesn't 100% faithfully represent either Mono.Cecil's syntax or my own
// There are actually a lot of annoying casts involved, omitted for sanity
// 4) Obviously, if the method is invalid, throw
if (methodInvalid)
{
throw new Exception(String.Format("Bad developer! BAD! {0}", method.Name));
}
}
Trust me, the actual code is even uglier looking than my pseudocode.... :-)
But Mono.Cecil just might be my new favorite toy.
I now have a method that refuses to be run its main body unless the calling code "promises" to also call a second method afterwards. It's like a strange kind of code contract. I'm actually thinking about making this generic and reusable. Would any of you have a use for such a thing? Say, if it were an attribute?
What if you made it so Init and With don't return objects of type FluentClass? Have them return, e.g., UninitializedFluentClass which wraps a FluentClass object. Then calling .Save(0 on the UnitializedFluentClass object calls it on the wrapped FluentClass object and returns it. If they don't call Save they don't get a FluentClass object.
In Debug mode beside implementing IDisposable you can setup a timer that will throw a exception after 1 second if the resultmethod has not been called.
Use an out parameter! All the outs must be used.
Edit: I am not sure of it will help, tho...
It would break the fluent syntax.

Persist List<int> through App Shutdowns

Short Version
I have a list of ints that I need to figure out how to persist through Application Shutdown. Not forever but, you get the idea, I can't have the list disappear before it is dealt with. The method for dealing with it will remove entry's in the list.
What are my options? XML?
Background
We have a WinForm app that uses Local SQL Express DB's that participate in Merge Replication with a Central Server. This will be difficult to explain but we also have(kind of) an I-Series 400 Server that a small portion of data gets written to as well. For various reasons the I-Series is not available through replication and as such all "writes" to it need to be done while it is available.
My first thought to solve this was to simply have a List object that stored the PK that needed to be updated. Then, after a successful sync, I would have a method that checks that list and calls the UpdateISeries() once for each PK in the list. I am pretty sure this would work, except in a case where they shut down innappropriately or lost power, etc. So, does anyone have better ideas on how to solve this? XML file maybe, though I have never done that. I worry about actually creating a Table in SQL Express because of Replication....maybe unfounded but...
For reference, UpdateISeries(int PersonID) is an existing Method in a DLL that is used internally. Re-writting it, as a potential solution to this issue, really isn't viable at the time.
Sounds like you need to serialize and deserialize some objects.
See these .NET topics to find out more.
From the linked page:
Serialization is the process of converting the state of an object into a form that can be persisted or transported. The complement of serialization is deserialization, which converts a stream into an object. Together, these processes allow data to be easily stored and transferred.
If it is not important for the on-disk format to be human readable, and you want it to be as small as possible, look at binary serialization.
Using the serialization mechanism is probably the way to go. Here is an example using the BinaryFormatter.
public void Serialize(List<int> list, string filePath)
{
using (Stream stream = File.OpenWrite(filePath))
{
var formatter = new BinaryFormatter();
formatter.Serialize(stream, list);
}
}
public List<int> Deserialize(string filePath)
{
using (Stream stream = File.OpenRead(filePath)
{
var formatter = new BinaryFormatter();
return (List<int>)formatter.Deserialize(stream);
}
}
If you already have and interact with a SQL database, use that, to get simpler code with fewer dependencies. Replication can be configured to ignore additional tables (even if you have to place them in another schema). This way, you can avoid a number of potential data corruption problems.

"Magic" constants in C# like PHP has?

I am building a logging control for a C# project and would like to be able to call it with the name of the current source code File, Line, Class, Function, etc. PHP uses "magic constants" that have all of this info: http://php.net/manual/en/language.constants.predefined.php but I don't see anything like that in the C# compiler language.
Am I looking for something that doesn't exist?
Using the StackTrace/StackFrame classes, you can have your control find out where it's been called from, rather than passing it that information:
private static StringBuilder ListStack(out string sType)
{
StringBuilder sb = new StringBuilder();
sType = "";
StackTrace st = new StackTrace(true);
foreach (StackFrame f in st.GetFrames())
{
MethodBase m = f.GetMethod();
if (f.GetFileName() != null)
{
sb.AppendLine(string.Format("{0}:{1} {2}.{3}",
f.GetFileName(), f.GetFileLineNumber(),
m.DeclaringType.FullName, m.Name));
if (!string.IsNullOrEmpty(m.DeclaringType.Name))
sType = m.DeclaringType.Name;
}
}
return sb;
}
(I used this code to get the call stack of the currently executed method, so it does more than you asked for)
The StackTrace/StackFrame classes will give you quite a bit of this, though they can be quite expensive to construct.
You can ask the system for a stack trace, and you can use reflection. Details are coming.
__LINE__
__FILE__
__DIR__
__FUNCTION__ (does not really exist in C#)
__CLASS__
__METHOD__
__NAMESPACE__
This is a start:
http://www.csharp-examples.net/reflection-callstack/
http://www.csharp-examples.net/reflection-calling-method-name/
Assembly.GetExecutingAssembly().FullName
System.Reflection.MethodBase.GetCurrentMethod().Name
You will get better information in Debug (non-optimized) build. PhP might always have access to all that stuff, but it ain't the fastest gun on this planet. Play with it and let me know what is missing.
There are methods to get this type of data. It depends on what data you want.
__CLASS__ : If you want the current classname you'll need to use reflection.
__LINE__ : I'm not sure what "The current line number of the file" means, I'll take a guess and say it's how many lines in the file. That can be done by opening the file and doing a line count. This can be done via the File class, the FileInfo class may also work.
__DIR__ :Getting the directory of the file is done by using the DirectoryInfo class.
__FUNCTION__ and __METHOD__: Function name (method name), this can be retrieved via reflection.
__NAMESPACE__ :Namespace an be retrieved via reflection
Using Type, the best you can really do is get information about the current class. There is no means to get the file (though you should generally stick to one class per file), nor line number, nor function using Type.
Getting a type is simple, for example, this.getType(), or typeof(MyClass).
You can get the more specific details by generating a StackTrace object and retrieving a StackFrame from it, but doing so repeatedly is a bad idea.
I think a more important question is perhaps: why do you need them? For trace debugging, your output is supposedly temporary, so whether it reflects an accurate line number or not shouldn't matter (in fact, I rarely ever include a line number in trace debugging). Visual Studio is also very useful as a true step debugger. What do you really need File, Class, Function, and Line Number for?
Edit: For error checking, use exceptions like they're meant to be used: for exceptional (wrong) cases. The exception will generate a stack trace pointing you right at the problem.
Many of the previous responders have provided excellent information; however, I just wanted to point out that accessing the StackFrame is exorbitantly expensive and probably shouldn't be done except for special cases. Those cases being an extremely chatty verbose mode for debugging corner cases or error logging and for an error you probably already have an Exception instance which provides the StackTrace. Your best performance will be as Bring S suggested by using Type. Also as another design consideration logging to the console can slow your application down by several orders of magnitude depending on the volume of data to display. So if there is a console sink having the writer operating on a worker thread helps tremendously.

Overhead of File/Directory.Exists in getter?

I have a class that has several properties that refer to file/directory locations on the local disk. These values can be dynamic and i want to ensure that anytime they are accessed, i verify that it exists first without having to include this code in every method that uses the values.
My question is, does putting this in the getter incur a performance penalty? It would not be called thousands of times in a loop, so that is not a consideration. Just want to make sure i am not doing something that would cause unnecessary bottle necks.
I know that generally it is not wise to optimize too early, but i would rather have this error checking in place now before i have to go back and remove it from the getter and add it all over the place.
Clarification:
The files/directories being pointed to by the properties are going to be used by System.Diagnostics.Process. i won't be reading/writing to these files/directories directly, i just want to make sure they exist before i spawn a child process.
Anything that's not a simple lookup or computation should go in a method, not a property. Properties should be conceptually similar to just accessing a field - if there is any additional overhead or chance of failure (and IO - even just checking a file exists - would fail that test on both counts) then properties are not the right choice.
Remember that properties even get called by the debugger when looking at object state.
Your question about what the overhead actually is, and optimising early, becomes irrelevant when looked at from this perspective. Hope this helps.
If you're that worried about performance (and you're right when you say that it's not a good idea to optimize too early), there are ways to mitigate this. If you consider that the expensive operation is the File I/O and you have lots of these going on, you could always look at using something like a Dictionary in your class. Consider this (fairly contrived) sample code:
private Dictionary<string, bool> _directories = new Dictionary<string, bool>();
private void CheckDirectory(string directory, bool create)
{
if (_directories.ContainsKey(_directories))
{
bool exists = Directory.Exists(directory);
if (create && !exists)
{
Directory.CreateDirectory(directory);
}
// Add the directory to the dictionary. The value depends on
// whether the directory previously existed or the method has been told
// to create it.
_directories.Add(directory, create || exists);
}
}
It's a simple matter later on to add those directories that don't exist by iterating over this list.
It is feasible for the path to exist at the point it is check but be moved/deleted in between that and the operation on it.
you may already know this and accept the risk but just so you are aware of it.
If you are going to do it anyway it doesn't matter whether it's in a property or not, just what granularity of checking you do (once per operation or once per group of operations)
If you use the non static FileInfo operations be aware that this object will cache its view on the file system.
This could be a good thing for you as you can control how often the cache is refreshed via the Refresh() method or it may lead to possible bugs in your code.
The usual try it first before worrying about performance recommendation applies but you indicate you are aware of this.
If you are reusing an object you should consider using the FileInfo class vs the static File class. The static methods of the File class does a possible unnecessary security check each time.
FileInfo - DirectoryInfo - File - Directory
EDIT:
My answer would still apply. To make sure your file exists you would do something like so in your getter:
if(File.Exists(string))
//do stuff
else
//file doesn't exist
OR
FileInfo fi = new FileInfo(fName);
if (fi.Exists)
//do stuff
else
//file doesn't exist
Correct?
What I am saying is that if your are looping through this logic thousands of time then use the FileInfo instance VS the static File class because you will get a negative performance impact if you use the static File.Exits method.

Categories