locked
How do I return 2 values (strings) from a Class/Function? RRS feed

  • Question

  • User-903716854 posted

    I have a simple class with a function that returns as single string (displayName from Active Directory) and that works fine.
    However what if I want to return 2 strings (displayName and Manager) from a single call?
    I know how to get Manager from AD, but do not know how to combine the 2 values in the return.

    public class CSActiveDirectory
    {
        public String DisplayName(String UserID)
        {
            PrincipalContext c = new PrincipalContext(ContextType.Domain, "myDomain");
            UserPrincipal principal = UserPrincipal.FindByIdentity(c, UserID);
            return principal.DisplayName;  // I also want to return Manager
        }
    

    If it of any consequence, I am using framework 3.5

    Thanks

    Friday, July 26, 2013 10:58 AM

Answers

  • User281315223 posted

    Using your example, you could likely just combine both of the classes within a single class file and populate that class based on the value of your Textbox as seen below :

    YourWebForm.aspx.cs

    using System;
    
    namespace YourProject
    {
        public partial class WebForm1 : System.Web.UI.Page
        {
            protected void Page_Load(object sender, EventArgs e)
            {
    
            }
    
            protected void GetValues(object sender, EventArgs e)
            {
                //Grab a YourClass object from an instance of CSActiveDirectory by passing in the "Username" through Input
                //Basically appending "1" and "2" to the contents of your txtINPUT field
                YourClass yourClass = new CSActiveDirectory().DisplayName(txtINPUT.Text);
    
                //Populate your Textboxes with the Results
                txtOUTPUT1.Text = yourClass.DisplayName;
                txtOUTPUT2.Text = yourClass.Manager;
            }
        }
    }

    YourClass.cs

    namespace YourProject
    {
        public class CSActiveDirectory
        {
            public YourClass DisplayName(string UserID)
            {
                //Populate your contents here
                var employee = UserID + "1";
                var manager = UserID + "2";
    
                //Return an instance of YourClass
                return new YourClass(employee, manager);
            }
        }
    
        public class YourClass
        {
            public string DisplayName { get; set; }
            public string Manager { get; set; }
    
            public YourClass(string displayName, string manager)
            {
                //Populate properties
                DisplayName = displayName;
                Manager = manager;
            }
        }
    }

    This should take in whatever the value of the contents of your txtInput Textbox is and append 1 and 2 to the value respectively and display the results in your output textboxes.


    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, July 29, 2013 10:09 AM

All replies

  • User281315223 posted

    The easiest method to handle this would be to create a class that would store each of the properties that you want to output and then you could simply return the class (after you populate it within your function) : 

    public class YourClass
    {
         public string DisplayName {get; set;}
         public string Manager { get; set;}
    
         public YourClass(string displayName, string manager)
         {
               //Populate properties
               DisplayName = displayName;
               Manager = manager;
         }
    }

    and then adjust your method accordingly : 

    public YourClass DisplayName(String UserID)
    {
            PrincipalContext c = new PrincipalContext(ContextType.Domain, "myDomain");
            UserPrincipal principal = UserPrincipal.FindByIdentity(c, UserID);
    
            //Get Manager here
            var manager = LogicToGetManager();
    
            //Return an instance of YourClass
            return new YourClass(principal.DisplayName, manager);
    }

    so then you would call your method and access those properties as seen below  :

    //Get names
    YourClass result = GetDisplayName("username");
    
    //Get DisplayName and Manager respectively
    var displayName = result.DisplayName;
    var manager = result.Manager;
    Friday, July 26, 2013 11:24 AM
  • User-903716854 posted

    Thanks for the reply Rion.
    Howvever I am getting various errors when trying to implement your solution.

    Maybe I am getting it completely wrong....

    I have a codefile YourClass.cs that contains the first 2 code sections that you suggested.
    I then have a codefile MyPage.cs that contains the 3rd code section.

    Any ideas?

    Friday, July 26, 2013 12:38 PM
  • User-1002157272 posted

    If you would like to return multiple values from a function in c# without needing to create a class to hold the values, your only option is output parameters.

    Output parameters are simple to use but they do have one "gotcha":

    an output parameter MUST be assigned within the method before returning to the caller.

    You are not required to assign a value to the output parameter before passing it to the method because of the requirement that it MUST be assigned within the method it is passed to before returning. If you do assign a value before passing it, it will be overwritten anyway.

    here is a usage example:

    public void ExampleMethod(string input, out output1, out output2)
    {
        // do some stuff here...
        
        output1 = "This is output value 1";
    
        output2 = "This is output value 2";
    }

    The above method does not return a value directly and only uses output parameters (signified by the "out" modifier before the parameter signtaure).

    Here's an example of using the above method:

    // notice these 2 variables have not been initialized
    
    string var1;
    string var2;
    
    
    ExampleMethod("test input", out var1, out var2);
    
    
    // now you can guarantee that val1 and val2 are initialized and have been assigned values from in "ExampleMethod"

    A method can return a value from the method body as normal still even when it contains output parameters, but you MUST be sure to assign the output parameters before exiting the method body or you will get an exception.

    There is no limit to how many output paremeters can be included in a method signature and they can be of any type.

    How this helps.

    Friday, July 26, 2013 12:56 PM
  • User281315223 posted

    It's likely just an issue of where you are referencing your new class being unable to actually access the implementation of the class itself.

    To make this a bit more clear, try including all of the code within a single area, which should remove any issues with referencing : 

    namespace YourApplication
    {
        public partial class YourWebForm : System.Web.UI.Page
        {
            protected void Page_Load(object sender, EventArgs e)
            {
                //Your Directory
                CSActiveDirectory directory = new CSActiveDirectory();
    
                //Get names
                YourClass result = directory.DisplayName("username");
    
                //Get DisplayName and Manager respectively
                var displayName = result.DisplayName;
                var manager = result.Manager;
            }
        }
    
        public class YourClass
        {
            public string DisplayName { get; set; }
            public string Manager { get; set; }
    
            public YourClass(string displayName, string manager)
            {
                //Populate properties
                DisplayName = displayName;
                Manager = manager;
            }
        }
    
        public class CSActiveDirectory
        {
            public YourClass DisplayName(String UserID)
            {
                PrincipalContext c = new PrincipalContext(ContextType.Domain, "myDomain");
                UserPrincipal principal = UserPrincipal.FindByIdentity(c, UserID);
    
                //Get Manager here
                var manager = LogicToGetManager();
    
                //Return an instance of YourClass
                return new YourClass(principal.DisplayName, manager);
            }
        }
    }

    Friday, July 26, 2013 1:01 PM
  • User-1910946339 posted

    You can use the builtin Tuple class by changing DisplayName to

    public Tuple<string, string> DisplayName(String UserID)
    {
       var c = new PrincipalConext(blah, blah);
       var principal = whatever;
       var manager = somethingInHere;
    
       return Tuple.Create(principal.DisplayName, manager.DisplayName);
    }

    your calling code probably has something that look like

    string theName = DisplayName(someID);

    you would change this to

    var twoNames = DisplayName(someID);

    Now twoNames.Item1 is the principal and twoNames.Item2 is the manager.

    Friday, July 26, 2013 10:09 PM
  • User-903716854 posted

    Hi Rion,

    OK, so I put all of the code in a single codefile and it works great.

    However, I want to create the class in a separate codefile as several of my webforms will need to use the displayname, manager name.

    Please could you tell me how to do this with MyWebform.aspx / MyWebform.aspx.cs plus myClass.cs

    Monday, July 29, 2013 5:00 AM
  • User281315223 posted

    If you want to use a seperate class, you'll just need to ensure that the namespace that is being targeted by both your Page and your class match (so that you can access your class within your page).

    YourClass.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    
    //As long as the Namespace matches the rest of your Project, you can simply include it
    //within a seperate file
    namespace YourProject
    {
        public class YourClass
        {
            public string DisplayName { get; set; }
            public string Manager { get; set; }
    
            public YourClass(string displayName, string manager)
            {
                //Populate properties
                DisplayName = displayName;
                Manager = manager;
            }
        }
    }

    However, if your namespace differs for your class (and you wanted to place it in some kind of "helpers" folder), you might be referencing it within your page through a "using statement" as seen below : 

    YourWebForm.aspx.cs

    //This will need to match the namespace defined in your YourClass.cs file
    //(Unnecessary if it matches your existing namespace) using YourProject.Helpers; namespace YourProject { public partial class YourWebForm : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { } public class CSActiveDirectory { public YourClass DisplayName(String UserID) { PrincipalContext c = new PrincipalContext(ContextType.Domain, "myDomain"); UserPrincipal principal = UserPrincipal.FindByIdentity(c, UserID); //Get Manager here var manager = LogicToGetManager(); //Return an instance of YourClass return new YourClass(principal.DisplayName, manager); } } } }

    or you can fully-qualify the class itself with out requiring a using statement : 

    return new YourProject.Helpers.YourClass(principal.DisplayName, manager);

    Monday, July 29, 2013 7:47 AM
  • User-903716854 posted

    Oh dear, I am still struggling with this I feel really dumb!

    Let's strip it right back to basics....
    I have a number of webforms in my application that require the same functionality as other pages (eg, determining employee/manager information). Therefore I want to be able to call up that information in the simplest way possible.

    In the interest of simplicity, we can forget the employee/manager piece for now and just pass a Value (txtINPUT on the form) when a button is clicked. This will then populate 2 Textboxes on the same form (txtOUTPUT1 and txtOUTPUT2).

    Again, for simplicity, let's say that I INPUT "GARY" and what I want returned is "GARY1" (INPUT + "1") and "GARY2" (INPUT + "2")

    I really appreciate your perserverance with this.

    YourWebForm.aspx

    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="YourWebForm.aspx.cs" Inherits="YourWebForm" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
            <asp:TextBox ID="txtINPUT" runat="server" />
            <br />
            <asp:TextBox ID="txtOUTPUT1" runat="server" />
            <br />
            <asp:TextBox ID="txtOUTPUT2" runat="server" />
            <br />
            <asp:LinkButton ID="MyButton" runat="server" OnClick="GetValues" Text="Click Me" />
        </div>
        </form>
    </body>
    </html>
    

    YourWebForm.aspx.cs

    using System;
    using System.Data;
    using System.Data.Sql;
    using System.Data.SqlClient;
    using System.Configuration;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    
    using YourProject;
    
        public partial class YourWebForm : System.Web.UI.Page
        {
            protected void Page_Load(object sender, EventArgs e)
            {
    
            }
    
            protected void GetValues(object sender, EventArgs e)
            {
                //Pass the Text from txtINPUT and get the return values from the Class
                
                txtOUTPUT1.Text = "????";
                txtOUTPUT2.Text = "????";
            }
    
            // *** I am not understanding why the below is in the webform cs ***
            public class CSActiveDirectory
            {
                public YourClass DisplayName(string UserID)
                {
                    var employee = "";
                    var manager = "";
    
                    //Return an instance of YourClass
                    return new YourClass(employee, manager);
                }
            }
        }
    

    YourClass.cs

    ????


     

     

    Monday, July 29, 2013 9:41 AM
  • User-1360095595 posted

    If it's simplicity you're after then why not use the Tuple idea suggested before? It's quite simple. 

    Monday, July 29, 2013 10:00 AM
  • User-903716854 posted

    Because I am using framework 3.5 and as far as I am aware, Tuple was only introduced in 4.0

    Monday, July 29, 2013 10:06 AM
  • User281315223 posted

    Using your example, you could likely just combine both of the classes within a single class file and populate that class based on the value of your Textbox as seen below :

    YourWebForm.aspx.cs

    using System;
    
    namespace YourProject
    {
        public partial class WebForm1 : System.Web.UI.Page
        {
            protected void Page_Load(object sender, EventArgs e)
            {
    
            }
    
            protected void GetValues(object sender, EventArgs e)
            {
                //Grab a YourClass object from an instance of CSActiveDirectory by passing in the "Username" through Input
                //Basically appending "1" and "2" to the contents of your txtINPUT field
                YourClass yourClass = new CSActiveDirectory().DisplayName(txtINPUT.Text);
    
                //Populate your Textboxes with the Results
                txtOUTPUT1.Text = yourClass.DisplayName;
                txtOUTPUT2.Text = yourClass.Manager;
            }
        }
    }

    YourClass.cs

    namespace YourProject
    {
        public class CSActiveDirectory
        {
            public YourClass DisplayName(string UserID)
            {
                //Populate your contents here
                var employee = UserID + "1";
                var manager = UserID + "2";
    
                //Return an instance of YourClass
                return new YourClass(employee, manager);
            }
        }
    
        public class YourClass
        {
            public string DisplayName { get; set; }
            public string Manager { get; set; }
    
            public YourClass(string displayName, string manager)
            {
                //Populate properties
                DisplayName = displayName;
                Manager = manager;
            }
        }
    }

    This should take in whatever the value of the contents of your txtInput Textbox is and append 1 and 2 to the value respectively and display the results in your output textboxes.


    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, July 29, 2013 10:09 AM
  • User-903716854 posted

    Rion, I am ever so grateful for all your help (and for putting up with my constant questionning)

    This is a huge relief for me and I should now be able to implement the additional functionality such as Active Direectory lookups, etc/

    YOU ARE A STAR!

    Many, Many Thanks!!!!!

    Monday, July 29, 2013 10:20 AM