8

So I'm not actually sending arguments, but setting a class variable to a certain value, then using it again in another method. Is this the "best practice" way to do things? If not, I'd be interested in learning the correct way. Thanks! Can/Should the arguments be sent some other way?

private string PrintThis;

public void PrintIt(string input){
    PrintThis = input; //SETTING PrintThis HERE
    static private PrintDocument pd = new PrintDocument();
    pd.PrintPage += new PrintPageEventHandler(PrintDocument_PrintSomething);
    pd.Print();
}
private void PrintDocument_PrintSomething(Object sender, PrintPageEventArgs e) {
    e.Graphics.DrawString(PrintThis, new Font("Courier New", 12), Brushes.Black, 0, 0);
    //USING PrintThis IN THE ABOVE LINE
}
sooprise
  • 22,657
  • 67
  • 188
  • 276

3 Answers3

10

Closures were introduced into the language to solve this very problem.

By capturing the appropriate variable, you can give it storage that 'outlives' the containing method:

// Note that the 'input' variable is captured by the lambda.
pd.PrintPage += (sender, e) => Print(e.Graphics, input);
...

static void Print(Graphics g, string input) { ... }

Do note that this very much a convenience feature; the way the compiler solves this problem on your behalf is suspiciously similar to your own, existing solution. (There are certain differences, e.g. the captured variable ends up as a field of a newly created object of some other (generated) class. Your existing solution does not do this: you have one 'temporary' storage location per instance of your class rather than per call to PrintIt, which is not good - it isn't thread-safe, for example)

Community
  • 1
  • 1
Ani
  • 111,048
  • 26
  • 262
  • 307
  • In the Print method, is it better to send the argument e.Graphics instead of just e? Or is it not really a big deal? – sooprise Feb 11 '11 at 17:06
  • @sooprise: That's up to you - I figured it doesn't need the whole `PrintPageEventArgs`, so let's just give it what it needs . Sorry, maybe I shouldn't have done that 'refactoring'; it detracts from the actual issue. – Ani Feb 11 '11 at 17:08
  • I have another question about closure. It just occurred to me that my code is wrong in the OP. the variable "pd" is actually a private class variable that is used in both "PrintIt" and "PrintDocument_PrintSomething". Should "pd" also be passed as an argument like "input" (since it's defined outside of two methods and used by both)? – sooprise Feb 11 '11 at 17:13
  • @sooprise: That depends. Where is it being assigned? Is a `PrintDocument` instance *logically* tied to a particular `PrintIt` call or to an instance of the containing class? – Ani Feb 11 '11 at 17:14
  • I would say that it is tied to a particular instance of the containing class. – sooprise Feb 11 '11 at 17:16
  • @sooprise: Then there's no reason to capture it. Of course, that means the `PrintSomething` method can't be `static` anymore because it needs a reference to the containing object. You can of course keep it static and capture `this`, but that would be strange.. – Ani Feb 11 '11 at 17:17
1

Not normally, but for this API (WinForms printing) it is the usual approach.

Consider that PrintThis is not just a variable but your "model" or "document".

H H
  • 263,252
  • 30
  • 330
  • 514
0

Alternatively, you can use inheritance:

class MyPrintDocument : PrintDocument
{
  public delegate void MyPrintPageEventHandler (object, PrintPageEventArgs, object); // added context!
  public event MyPrintPageEventHandler MyPrintPageEvent;

  public MyPrintDocument (object context) { m_context = context; }
  protected void OnPrintPage (PrintPageEventArgs args)
  {
    // raise my version of PrintPageEventHandler with added m_context
    MyPrintPageEvent (this, args, m_context);
  }
  object m_context;
}

public void PrintIt(string input)
{
  MyPrintDocument pd = new MyPrintDocument(input);
  pd.MyPrintPage += new MyPrintPageEventHandler (PrintDocument_PrintSomething);
  pd.Print();
}

private void PrintDocument_PrintSomething(Object sender, PrintPageEventArgs e, object context)
{
   e.Graphics.DrawString((string) context, new Font("Courier New", 12), Brushes.Black, 0, 0);
}
Skizz
  • 69,698
  • 10
  • 71
  • 108
  • Is inheritance the "Better Practice" (as compared to closure?) – sooprise Feb 11 '11 at 17:07
  • @sooprise: This will work in all versions of C#, closures are a recent introduction (3.5?). As for "Better Practice", that's hard to say. – Skizz Feb 11 '11 at 17:19