Best practice with dynamic string / List <string> parameters
I want to pass either a string or List<string> as a parameter, like how I could do it in JavaScript, and then evaluate what type it is and take the appropriate action. Now I can do it as follows:
public static class TestParser { static void Parse(string inputFile) { // Lots of code goes in here } static void Parse(List<string> inputFileList) { // Lots of code goes in here too } } What the code does inside these methods is basically analysis with some programs, either a single file or a list of files, depending on the type.
If I have a lot of code, do I need to duplicate it, or should I create a sub method that will contain the code, or is there another cool way I can do in C #?
Depending on what Parse () should do, a reasonable template might be
static void Parse(string inputFile) { // Lots of code goes in here } static void Parse(List<string> inputFileList) { foreach (var inputFile in inputFileList) Parse(inputFile); } UPDATE
An alternative was to create a new List<string>() { inputFile} and call Parse(List<string>) instead of splitting the processing code into a separate method.
static void Parse(List<string> inputFileList) { // Lots of code goes in here too } static void Parse(string inputFile) { Parse(new List<string>() { inputFile }); } In almost all cases, it is only a matter of style. I prefer my solution because at first glance (at least for me), and because I worked on systems with very large volumes, where the CLR's ability to get rid of short-lived objects became a performance issue. 99.99% even performance-critical applications will not work in this particular problem.
Any difference in performance will only occur if you have such a large volume of individual calls that you press CLR CG on the breakpoint. If you have a sufficiently high or high volume of method calls, // Lots of code goes in here processing time is likely to lead to the fact that the cost of creating a new list is almost immeasurable.
For almost all cases, the two approaches differ only in style and fit together.
List<T> , inside, is not a list (in the sense of CS). This is an array that is redistributed as needed. Assuming that the parsing logic is identical regardless of whether the method has passed 1, 2 or more lines, I would do something like this, implementing logic to process one element:
static void Parse( string s ) { // core logic for processing an individual item } Then add the appropriate overloads. I would first add a generic version:
static void Parse( params string[] list ) { Parse( (IEnumerable<string> list ) ; } static void Parse( IEnumerable<T> list ) { foreach( string s in list ) { Parse(s) ; } return ; } The first version above ( params string[] ) allows you to call a method with variable numbers of arguments:
Parse( "foo" , "bar" ) ; Parse( "foo" , "bar" , "baz" , "bat" ) ; The second version above ( IEnumerable<T> ) accepts everything that IEnumerable<T> implements: almost any standard collection, so it will accept things like:
List<string> listOfStrings = PopulateList() ; Parse( listOfStrings ) ; string[] arrayOfStrings = listOfStrings().ToArray() ; Parse( arrayOfStrings ) ; Not to mention things like HashSet<string> , TreeSet<string> , etc.
You can even use deferred LINQ execution with this overload:
public static IEnumerable<string> ReadStringsFromFile( string fileName ) { using ( StreamReader reader = File.OpenText( fn ) ) { string s ; while ( null != (s=reader.ReadLine()) ) { yield return s ; } } } ... Parse( ReadStringsFromFile() ) ; which combines the methods: the file will be considered a line at a time and each line is processed individually.
You can also write an extension method to combine method calls:
public static void ParseEach( this IEnumerable<T> string strings ) { foreach ( string s in strings ) { Parse(s) ; } } which allows you to say something like
ReadStringsFromFile().ParseEach() ;