1

I am trying to make an application that will do something on every file in a directory.

That something should be some method. But since I don't know which method, exactly, I am trying to make it so my "iterating" method takes an argument of any method or some sort of method reference, so he can call it on every file.

The point is that there are many options on what to do with each file and the user chooses the one he wants. The options must also be open for extension, so a week from now I may decide to add a new one, that is why I need:

A method that can call any method with no prior knowledge of its signature.

Actions and Functions on't work for me, because they need a concrete signature. So do delegates, as far as I know and (I think) they can't be passed as a method parameter.

Example of what I want to achieve:

void Iterate(DirectoryInfo dir, method dostuff)
{
    foreach(var file in dir.GetFiles())
    {
        dostuff(file);
        //And this is the point where I feel stupid...
        //Now I realise I need to pass the methods as Action parameters,
        //because the foreach can't know what to pass for the called method
        //arguments. I guess this is what Daisy Shipton was trying to tell me.
    }
}
J. Doe
  • 1,147
  • 1
  • 13
  • 21
  • 5
    Suppose I pass you a method with 5 parameters. The only information your code will have is the file name, presumably. That could be used for one parameter - what arguments would you want to provide for the other four? I *really* think you'll want `Action` or similar. – Jon Skeet May 30 '18 at 09:41
  • This might be something you want to do with the decorator pattern. Example [link](https://www.codeproject.com/Articles/479635/UnderstandingplusandplusImplementingplusDecoratorp). For each possible option you create a concretedecorator class with it's own logic and number of parameters. – Kjell Derous May 30 '18 at 09:43
  • 1
    To further Daisy's point - which means any other parameterization you might apply to these arbitrary methods needs to be *captured* - perhaps using a lambda, etc, which means you should always be able to *transform* your arbitrary methods into a `Action` taking a single parameter and it's that *transformed* method that your code should accept – Damien_The_Unbeliever May 30 '18 at 09:43
  • @DaisyShipton and Damien: ...wat? I don't understand your point(s). My aim is to be able to perform both a copy operation (which requires only a string as target directory) and a rename operation (which would require "old string" and "new string" parameters). Which is the part that is making it hard. – J. Doe May 30 '18 at 09:56
  • Let's take the rename operation as an example - where would the information about what to rename the file *to* come from? – Jon Skeet May 30 '18 at 09:58
  • @DaisyShipton, user input. In one form or another. Wait, I just added an "example" and think I figured out what you mean. You mean that the iterating method can't know what to pass as arguments to the called method, right? – J. Doe May 30 '18 at 09:59
  • @J.Doe: Exactly. Think about how that method is meant to call the unknown method - it's got to provide arguments for all parameters, and it wouldn't know the user input. – Jon Skeet May 30 '18 at 11:01

1 Answers1

4

Your idea can be implemented, however the function which does something must always have the same signature; for this you could use the predefined delegate types. Consider the following snippet.

public void SomethingExecuter(IEnumerable<string> FileNames, Action<string> Something)
{
    foreach (string FileName in FileNames)
    {
        Something(FileName);
    }
}

public void SomethingOne(string FileName)
{
    // todo - copy the file with name FileName to some web server
}

public void SomethingTwo(string FileName)
{
    // todo - delete the file with name FileName
}

The first function could be used as follows.

SomethingExecuter(FileNames, SomethingOne);
SomethingExecuter(FileNames, SomethingTwo);

I hope this helps.

Codor
  • 17,447
  • 9
  • 29
  • 56
  • 1
    Copy/pasted `SomethingOne` too fast you did. Plus I believe there should be a `void` after `public` for both of those – Rafalon May 30 '18 at 09:50
  • 1
    @Rafalon Addressed your suggestions I have. – Codor May 30 '18 at 09:53
  • Oh, so you are saying I should make all my *something* methods be like Actions? – J. Doe May 30 '18 at 09:57
  • 1
    @J.Doe no, I think you could also call `SomethingExecuter(FileNames, x => [whatever]);` with lambas – Rafalon May 30 '18 at 09:58
  • @J.Doe No, this was just for illustration purposes. Your idea makes most sense when all functions have the same signature. – Codor May 30 '18 at 10:00
  • D'oh! I just realised why they all need the same signature (after I added an example in my question). – J. Doe May 30 '18 at 10:06