MTeck
MTeck

Reputation: 1688

Use variable in place of function name

I'm using the following right now:

foreach (string file in files) {
    switch (filetype.Value) {
        case "ReadFile":
            ReadFile(file);
            break;
        case "ReadMSOfficeWordFile":
            ReadMSOfficeWordFile(file);
            break;
        case "ReadMSOfficeExcelFile":
            ReadMSOfficeExcelFile(file);
            break;
        case "ReadPDFFile":
            ReadPDFFile(file);
            break;
    }
}

It works, but it feels kinda wrong. The Python way would be something more like this:

foreach string file in files:
    filetype.Value(file)

I have a really hard time imagining that C# can't do something like this. It may be that my Google skills are bad, but I can't seem to figure it out.

SOLUTION

public static readonly IDictionary<string, Action<string>> FileTypesDict = new Dictionary<string,Action<string>> {
    {"*.txt", ReadFile},
    {"*.doc", ReadMSOfficeWordFile},
    {"*.docx", ReadMSOfficeWordFile},
    {"*.xls", ReadMSOfficeExcelFile},
    {"*.xlsx", ReadMSOfficeExcelFile},
    {"*.pdf", ReadPDFFile},
};

 

foreach (KeyValuePair<string, Action<string>> filetype in FileTypesDict) {
    string[] files = Directory.GetFiles(FilePath, filetype.Key, SearchOption.AllDirectories);
    //System.Reflection.MethodInfo ReadFileMethod = ReadFile.GetType().GetMethod(filetype.Value);
    foreach (string file in files) {
        FileTypesDict[filetype.Key](file);
    }
}

Upvotes: 7

Views: 8294

Answers (6)

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726559

You can do it with some preparation using delegates, like this:

private static readonly IDictionary<string,Action<string>> actionByType =
    new Dictionary<string,Action<string>> {
        {"ReadFile", ReadFile}
    ,   {"ReadMSOfficeWordFile", ReadMSOfficeWordFile}
    ,   {"ReadMSOfficeExcelFile", ReadMSOfficeExcelFile}
    ,   {"ReadPDFFile", ReadPDFFile}
    };

When it is time to call your action, do it as follows:

actionByType[actionName](file);

Upvotes: 9

Red Taz
Red Taz

Reputation: 4179

If you're looking for a way to avoid the explicit mapping of method names to string values you could use reflection to do dynamic method invocation (this assumes filetype.Value is of type String)

String method_name = String.Empty;
foreach (string file in files) {
    method_name = filetype.Value;
    System.Reflection.MethodInfo method = this.GetType().GetMethod(method_name);
    method.Invoke(this, new object[]{file});
}

Upvotes: 0

Khan
Khan

Reputation: 18142

I believe what you're looking for will need some refactoring of your code.

All of your "cases" (TextFile, MSOfficeWordFile, MSOfficeExcelFile, PdfFile) should be their own classes which implement a single interface.

Your interface should be named something like "IReadableFile" and specify a method named "ReadFile()".

Each class should have their own implementation of "ReadFile()"

Example:

public interface IReadableFile
{
    void ReadFile();
}

public class MSOfficeWordFile : IReadableFile
{
    public void ReadFile()
    {
        ReadMSOfficeWordFile(file);
    }
} 

foreach(IReadableFile file in files)
    file.ReadFile();

Code may contain some mistakes, but I hope you get the idea.

Upvotes: 3

Kharaone
Kharaone

Reputation: 597

You could also use reflection (if you're okay with the different overhead that can bring) Check this solution

Hope that helped

Upvotes: 1

Guffa
Guffa

Reputation: 700312

You can use a delegate:

Action<string> action;
switch (filetype.Value) {
  case "ReadFile":
    action = ReadFile;
    break;
  case "ReadMSOfficeWordFile":
    action = ReadMSOfficeWordFile;
    break;
  case "ReadMSOfficeExcelFile":
    action = ReadMSOfficeExcelFile;
    break;
  case "ReadPDFFile":
    action = ReadPDFFile;
    break;
  default: 
    throw new NotImplementedException("Unhandled file type '"+filetype.Value+"'.");
}
foreach (string file in files) {
  action(file);
}

Upvotes: 6

Ry-
Ry-

Reputation: 224904

You could keep a Dictionary of delegates, as the simplest way:

Dictionary<string, Action<string>> fileReaders = new Dictionary<string, Action<string>>() {
    {"ReadFile", ReadFile},
    {"ReadOfficeWordFile", ReadOfficeWordFile},
    {"ReadOfficeExcelFile", ReadOfficeExcelFile},
    {"ReadPDFFile", ReadPDFFile}
};

Then call it like this:

fileReaders[fileType.Value](file);

Depending on what your methods return, you may have to change the type of the delegate (Action<string> means void something(string someparam) as a method signature, for example) as well.

Upvotes: 4

Related Questions