will this cause a memory leak in C#

masfenix

I am learning C# again after a whole lot of years. I did C# programming back in the 2.0 days. The language has indeed evolved, and its fantastic. That being said, I am making a W8/WP8 universal app. Basically when the app launches, the constructor runs a method. This method checks for a connection and if the connection is enabled, the program flows forward.

private async void UpdateInformationSection(IUICommand command) {
    InformationModel GeneralInformationModel = new InformationModel
    {
        apistatus = await voip_service.isAPIEnabled(),
        apimessage = await voip_service.GetAPIMessage(),
        currentbalance = await voip_service.getBalance(),
        currentip = await voip_service.getIP()
    };

    if (GeneralInformationModel.apistatus == false) {
        var msgdialog = new MessageDialog(
            "Please go to voip.ms to enable your API. You will need to know the IP address of the device on which this application is installed",
            "API connection could not be established");
        // Add commands and set their callbacks; both buttons use the same callback function instead of inline event handlers

        msgdialog.Commands.Add(new UICommand(
            "Try again", new UICommandInvokedHandler(this.UpdateInformationSection)));

        // Show the message dialog
        await msgdialog.ShowAsync();
    }

    // set the data context for the first section of the hub
    // so we can use bindings.
    mainpagehub.Sections[0].DataContext = GeneralInformationModel;

So if you notice, if the connection fails then we have a message dialog popped up. There is a "try again" button the popup. When users click this button, it has a "callback function" associated with it (new stuff to me, I guess its like an event handler?). Anyways, instead of coding a new method, I made the callback method the same as the current method the messagebox is executed in. So basically what I did was added an argument so I have this UpdateInformationSection(IUICommand command). And then the callback function is the same method.

What I am scared of: Everytime they click the "try again" button, will it destroy the old instance of it? In other words, when they click the "try again" button, does the method finish executing? Otherwise I am imagining a scenario where the method is called again and again and each method is stuck in limbo (if this makes any sense).

Also, in my constructor when the method is FIRST called ,I had to change it to

//Update HUB Sections.            
// send null as argument since its not coming from a "command button"
// the argument is required when the API connection cant be established
// and thus a modal dialog comes up with a "try again" command button.
UpdateInformationSection(null);    

Is it okay sending a "null" like that to the "command" argument? What is the right procedure here.

Peter Duniho

For sure, there's no true recursion here, because you are using async. But it is possible (probable, actually, but I haven't double-checked) that the MessageDialog does not complete the ShowAsync() method call until your own command delegate completes. This would result in the multiple instances of MessageDialog remaining reachable until you finally don't show it, preventing them from being garbage-collected (i.e. the closest you can get to a real memory leak with managed objects).

IMHO, the method would be better-implemented if you avoided this potential re-entrancy, by queuing the method for execution again instead of call it directly. That could look something like this:

private async void UpdateInformationSection(IUICommand command) {
    InformationModel GeneralInformationModel = new InformationModel
{
    apistatus = await voip_service.isAPIEnabled(),
    apimessage = await voip_service.GetAPIMessage(),
    currentbalance = await voip_service.getBalance(),
    currentip = await voip_service.getIP()
};

if (GeneralInformationModel.apistatus == false) {
    var msgdialog = new MessageDialog(
        "Please go to voip.ms to enable your API. You will need to know the IP address of the device on which this application is installed",
        "API connection could not be established");
    // Add commands and set their callbacks; both buttons use the same callback function instead of inline event handlers

    msgdialog.Commands.Add(new UICommand("Try again"));

    // Show the message dialog
    await msgdialog.ShowAsync();

    var _ = CoreWindow.GetForCurrentThread().Dispatcher
        .RunAsync(CoreDispatcherPriority.Normal,
            () => { var ignoreTask = UpdateInformationSection(command); });
    return;
}

// set the data context for the first section of the hub
// so we can use bindings.
mainpagehub.Sections[0].DataContext = GeneralInformationModel;

This way, each time the MessageDialog is displayed, it's given the opportunity to go ahead and close before you redisplay it.

The above assumes "Try again" really is the only option you present. Of course, if you have additional options, you can use the UICommand object to distinguish between the selected option and do the appropriate thing; "Try again" would do the above call to RunAsync() the method again, while other options would do whatever they do.

All that said, personally I think it would be better to avoid this pattern. Presumably, the user did something else that originally initiated this dialog. At the very least, there ought to also be a "Cancel" option as an alternative to "Try Again". And IMHO it would actually be better to just present this as an alert with the default "Close", so that the user simply is taken back to wherever they were, so that after they fix the configuration issue, they can just explicitly attempt the action/operation again.

I'm of course making some assumptions about the program here. Lacking specific details, I admit there could be some compelling reason to do it the way you are now instead. But at least be sure this is really the best way to do it. Sticking a user in a potentially endless loop seems a bit "off" to me. :)

EDIT:

To elaborate on this bit of code:

    var _ = CoreWindow.GetForCurrentThread().Dispatcher
        .RunAsync(CoreDispatcherPriority.Normal,
            () => { var ignoreTask = UpdateInformationSection(command); });

The RunAsync() method causes the given delegate to be executed in the Dispatcher's thread, i.e. the UI thread for your program. This is where the method is already (presumably) running, since it's a command invoked by some UI object. Doing it this way allows the method to be re-invoked, but in a non-re-entrant way. I.e. the current method call is allowed to complete and return before the next one starts. This eliminates any recursive aspect.

The invoked delegate itself — () => { var ignoreTask = UpdateInformationSection(command); } — using the statement body lambda syntax, is simply the method call to invoke your command method again.

Finally, both the RunAsync() method and your command method are async methods, returning a Task instance. In this particular case, we don't need to wait for them to finish, so there's no await, but if we don't do something with the return value the compiler will generate a warning. For me, the easiest, cleanest way to suppress the warning is to go ahead and copy the Task reference to a local variable, which is enough to make the compiler happy. The RunAsync() method is copied to a variable named _, which is what I usually use for variables that I don't actually need to use, while the command method's return value is copied to a variable named ignoreTask, named that way to be explicit about the purpose of the variable (which is to ignore the Task returned from your command method).

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

Will this cause a memory leak in c++?

From Dev

Will this cause a memory leak in c++?

From Dev

Why does "try catch" in Objective-C cause memory leak?

From Dev

Can reassigning a C style string cause a memory leak?

From Dev

Can reassigning a C style string cause a memory leak?

From Java

Is it possible to cause a memory leak in Rust?

From Dev

Finding the cause of a memory leak in Ruby

From Dev

Will below code cause memory leak?

From Dev

Will emptying an Array = [ ] cause memory leak?

From Dev

Does this Bitmap cause a memory leak?

From Java

Does never resolved promise cause memory leak?

From Dev

Will this method cause a memory leak when it throws an exception?

From Dev

Will returning nil in init cause a memory leak?

From Dev

Would this simple code cause a memory leak?

From Dev

Is subMap of NavigableMap going to cause memory leak?

From Dev

What is the cause of this strange Scala memory leak?

From Dev

Can the value of a ConditionalWeakTable cause a memory leak?

From Dev

recursive calls to ajax cause memory leak?

From Dev

Memory leak - probably 'cause of to many eventhandlers

From Dev

Is subMap of NavigableMap going to cause memory leak?

From Dev

Why does this function cause a memory leak?

From Dev

Angular.js - will this directive cause a memory leak?

From Dev

Will this method cause a memory leak when it throws an exception?

From Dev

Why does this JavaScript cause a memory leak?

From Dev

Unable to locate cause of memory leak in Android app

From Dev

Does 'new' cause a memory leak in Java?

From Dev

How can memory leaks cause information leak?

From Dev

Memory leak in replaceAll in C

From Dev

C pointer and memory leak

Related Related

HotTag

Archive