Solved

c# Variable return types

Posted on 2014-10-16
11
175 Views
Last Modified: 2014-10-20
Hello,
I am relatively new to c#. I have a c# application which uses a generic method to read dataset records. I would like to change the generic method so that when I pass specific table name (user_master, transaction_header etc..) the method will return the user_master object , transaction_header obj etc..). When an unspecified table name is encountered then it will just return the dataset which has just been been filled. The code below is just to illustrate what I am trying to do.


// read user master record
UserMaster myUser=new UserMaster();
tableName="user_master"
..
NavigateRecordsFlex(connStringKey, connString, sqlStmt, tableName);

// read transaction header record
TransactionHeader myTransHdr =new TransactionHeader();
tableName="transaction_header"
..
NavigateRecordsFlex(connStringKey, connString, sqlStmt, tableName);


public ????? NavigateRecordsFlex(string connStringKey, string connString, string sqlStmt, string tableName)
{
..
// If user master then return MyUser
if(tableName=="user_master")
{
return MyUser;
}
// If transaction Header then return MyTransHdr
if(tableName=="transaction_header")
{
return MyTransHdr;
}
return MyDataSet
}

I realize that I will have to change the return type of the method but I'm not sure what I need to change it to. Appreciate some advise on how best to achieve this.  

regards
Pat
0
Comment
Question by:pclarke7
11 Comments
 
LVL 69

Accepted Solution

by:
Éric Moreau earned 300 total points
ID: 40385768
you could return an object and you will have to cast it.

or always return a dataset which will contain only MyUser or MyTransHdr if that's the case. I really think it is the easiest solution.
0
 
LVL 40

Assisted Solution

by:Jacques Bourgeois (James Burger)
Jacques Bourgeois (James Burger) earned 100 total points
ID: 40385855
Éric solution would work, but unfortunately, you would have to repeat the logic anyway (or something similar) to know to what type to cast.

His second solution is OK, but once again, you will need to repeat the logic in order to know how to react to the value returned by the method. And by the way, do you really need a DataSet if you are fetching only one table. See http://www.experts-exchange.com/Programming/Languages/.NET/A_10298-When-to-use-a-DataSet-DataTable-DataReader-Command.html

It is not very good design to have a unique method for different purposes. Since no matter what you will need some kind of If to determine what was returned, why not create different methods and call the one that is appropriate.

If you really need want to have only one method, then what I would suggest is to create a class with 3 properties. One for each of the 3 different informations that you may return. Return an instance of that class. This way, you will not have to deal with any type of casting on the receiving end. If you need to return a DataSet (or DataTable) it will be in its own property, but that property will be set to null otherwise, with less overhead that returning a DataTable just to get a String.
0
 

Author Comment

by:pclarke7
ID: 40387564
Hi James & Eric,
I have been experimenting a little with the following:

    public class TransactionHeader
    {
        public string transCompanyId { get; set; }
        public string thisTransId { get; set; }
        public string origTransId { get; set; }
        public string transDescription { get; set; }
        public string transType { get; set; }
        public string screenSize { get; set; }
        public string securityLvl { get; set; }
        public string validated { get; set; }
        public string bypassBarcodeChecks { get; set; }
        public string nextNumberSystemCode { get; set; }
        public string alertEmailAddress { get; set; }
        public string emailSubject { get; set; }
        public string emailBody { get; set; }
        public string approvalRequired { get; set; }

        public TransactionHeader()
        {
            transCompanyId = " ";
            thisTransId = " ";
            origTransId = " ";
            transDescription = " ";
            transType = " ";
            transDescription = " ";
            screenSize = " ";
            securityLvl = " ";
            validated = "N";
            bypassBarcodeChecks = "N";
            nextNumberSystemCode = " ";
            alertEmailAddress = " ";
            emailSubject = " ";
            emailBody = " ";
            approvalRequired = "N";
        }
    }

    public class UserMaster
    {
        public string companyId { get; set; }
        public string userId { get; set; }      
        public string firstName { get; set; }
        public string lastName { get; set; }
        public string userGroup { get; set; }        
        public string userBusUnit { get; set; }
        public string initialMenu { get; set; }
        public string userEmail { get; set; }
        public string userPhone { get; set; }
        public string lastTranName { get; set; }
        public DateTime lastTranDate { get; set; }
        public string securityLvl { get; set; }
        public string promptTrans { get; set; }
        public string scanPfxSfxRqd { get; set; }
        public string password { get; set; }
        public string environmentsAvail { get; set; }       // Prod,Test,Dev,Uat
        public string tranHdrDbOvrConStrCode { get; set; }
        public string tranMstDbOvrConStrCode { get; set; }
        public string userMstDbOvrConStrCode { get; set; }
        public string errMsgDbOvrConStrCode { get; set; }
        public string promptMsgDbOvrConStrCode { get; set; }
        public string conStrDbOvrConStrCode { get; set; }
        public UserMaster()
        {
            companyId = " ";
            userId  = " ";
            firstName = " ";
            lastName = " ";
            userGroup = " ";
            userBusUnit = " ";
            initialMenu = " ";
            userPhone = " ";
            userEmail = " ";
            lastTranName = " ";
            lastTranDate = DateTime.MinValue;
            securityLvl = " ";
            promptTrans = " ";
            scanPfxSfxRqd = "Y";
            password = " ";
            environmentsAvail = " ";
            tranHdrDbOvrConStrCode = " ";
            tranMstDbOvrConStrCode = " ";
            userMstDbOvrConStrCode = " ";
            errMsgDbOvrConStrCode = " ";
            promptMsgDbOvrConStrCode = " ";
            conStrDbOvrConStrCode = " ";
         
        }
    }  


    [DataContract]
    public class Transaction
    {
        [DataMember]
        public string environment { get; set; }
        [DataMember]
        public string companyId { get; set; }
        [DataMember]
        public string thisTransId { get; set; }
        [DataMember]
        public string origTransId { get; set; }
        [DataMember]
        public string thisCompanyId { get; set; }

        public UserMaster MyUser { get; set; }

        public List<TransactionHeader> TranHdrList { get; set; }
       
        public List<DisplaySeq> DispSeqList { get; set; }

        //Other props/methods

        public Transaction()
        {
            thisTransId = " ";
            origTransId = " ";
            thisCompanyId = " ";

        }
    }
 }

The Transaction class contains a copy of the User master & Transaction header classes. I can then use a return type of Transaction to return both User and Header details. One thing is confusing. When I create a new instance of Transaction called MyTrans I would have expected that the User details and transaction header details would be initialized - but the are set to null. Why would they not be initialized on creation of a Transaction Object ?

regards
Pat
0
 
LVL 32

Assisted Solution

by:it_saige
it_saige earned 100 total points
ID: 40387611
It's because you don't initialize them anywhere, e.g. - In the constructor or by way of a private variable; and because they are reference types, the default value for a reference type is null.

If you don't want them unitialized, you will need to either create new instances in the constructor:
public Transaction()
{
	thisTransId = "";
	origTransId = "";
	thisCompanyId = "";
	MyUser = new MasterUser();
	TranHdrList = new List<TranHdrList>();
	DispSeqList = new List<DisplaySeq>();
}

Open in new window

Or use backing fields (private variables) for your properties:
private UserMaster _myUser = new UserMaster();
public UserMaster MyUser
{
	get { return _myUser; }
	set
	{
		if (!value.Equals(_myUser))
			_myUser = value;
	}
}

Open in new window


-saige-
0
 

Author Comment

by:pclarke7
ID: 40389292
Hi Saige,
in my application my classes are defined in Transaction.cs.  TransactionService.cs evokes a method in DataBaseIO.cs to read the User file. In this method I create the MyTrans object which now creates  a new MyUser

Transaction MyTrans=new Transaction();

public Transaction()
{
      thisTransId = "";
      origTransId = "";
      thisCompanyId = "";
      MyUser = new MasterUser();
      TranHdrList = new List<TranHdrList>();
      DispSeqList = new List<DisplaySeq>();
}

I can see in debug that MyUser is being initialized but immediately after returning from creating MyTrans & MyUser logic returns to the DataBaseIO method and MyUser is null.
Any idea what I'm doing wrong ?

regards
Pat
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 69

Expert Comment

by:Éric Moreau
ID: 40389329
isn't it too complex for nothing? return a dataset. sometimes the dataset will contain a MyUser datatable, other times a MyTransHdr datatable, other times a full dataset. Ensure that your tablename is correctly set and test the table name when your dataset gets back from your NavigateRecordsFlex methods.
0
 

Author Comment

by:pclarke7
ID: 40390024
Hi Eric,
I don't understand what you are try to say in your last comment. I have a generic database read method which I call to read any table. When it reads specific tables I would like to populate an instance of a class with the data. What you seem to be saying is that I should not have a generic read method and that I should have separate code for every file that I wish to read, which doesn't sound right to me.

I am still struggling with how to call a method that returns two or more data types. I  understand that the called method (eg NavigateRecordsFlex) can have multiple return statements as follows

if(tableName=="user_master")
{
return MyUser;
}
// If transaction Header then return MyTransHdr
if(tableName=="transaction_header")
{
return MyTransHdr;
}
return MyDataSet

But how do I code the Data type of NavigateRecordsFlex ?


NavigateRecordsFlex(connStringKey, connString, sqlStmt, tableName);


public ????? NavigateRecordsFlex(string connStringKey, string connString, string sqlStmt, string tableName)


If you could answer this question for me , it would help.

regards
Pat
0
 
LVL 69

Assisted Solution

by:Éric Moreau
Éric Moreau earned 300 total points
ID: 40390085
Your NavigateRecordsFlex needs to return a dataset:

public Dataset NavigateRecordsFlex(string connStringKey, string connString, string sqlStmt, string tableName)

Open in new window


Before returning your values, you need to ensure they are in a dataset:

if(tableName=="user_master")
{
var ds = new Dataset();
ds.Tables.Add(MyUser);
return ds;
}

Open in new window

0
 

Author Comment

by:pclarke7
ID: 40390367
Hi Eric,
I have changed NavigateRecordsFlex to return the last read  dataset rather than a variation of different types. However I am still having problems with the initialization of MyUser.  In the constructor of MyTran I create a new instance of MyUser and it's constructor in turn initializes the MyUser instance values. But when I next call NavigateRecordsFlex() I find that MyTrans is initialized but MyUser is null. How can it change from initialized to null ?

regards
Pat
0
 
LVL 69

Assisted Solution

by:Éric Moreau
Éric Moreau earned 300 total points
ID: 40390827
It is hard to say when we don't see code! Have you compared MyUser and MyTran to see if there are differences?
0
 

Author Closing Comment

by:pclarke7
ID: 40393080
Hi Guys,
Final solution was to return a dataset from DataBaseIO and implement additional methods such as ReturnMyUser() , ReturnMyTran() to return the various objects. Thanks to all for your input.

regards
Pat
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

A long time ago (May 2011), I have written an article showing you how to create a DLL using Visual Studio 2005 to be hosted in SQL Server 2005. That was valid at that time and it is still valid if you are still using these versions. You can still re…
Exception Handling is in the core of any application that is able to dignify its name. In this article, I'll guide you through the process of writing a DRY (Don't Repeat Yourself) Exception Handling mechanism, using Aspect Oriented Programming.
Internet Business Fax to Email Made Easy - With eFax Corporate (http://www.enterprise.efax.com), you'll receive a dedicated online fax number, which is used the same way as a typical analog fax number. You'll receive secure faxes in your email, fr…
Get a first impression of how PRTG looks and learn how it works.   This video is a short introduction to PRTG, as an initial overview or as a quick start for new PRTG users.

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now