Basic OOP question - why abstract?

J

jason

In the microsoft starter kit Time Tracker application, the data access
layer code consist of three cs files.

DataAccessHelper.cs
DataAcess.cs
SQLDataAccessLayer.cs

DataAcccessHelper appears to be checking that the correct data type is
used
DataAcess sets an abstract class and methods
SQLDataAccessLayer implements DataAcess


My noob question is why abstract? In Laymans terms please.

Granted, I'm still struggling with OOP concepts, but If you were coding
this application from scratch, and none of this code came from anywhere
else or was expected to be used anywhere would you really need all
three cs files and the inheritance of a baseclass public class
SQLDataAccess : DataAccess ?



Time Tracker can be found here:
http://msdn.microsoft.com/vstudio/express/vwd/starterkit/

The three sources in question:

====================
DataAccesshelper.cs:

using System;
using System.Configuration;

namespace ASPNET.StarterKit.DataAccessLayer {
public class DataAccessHelper {
public static DataAccess GetDataAccess() {
string dataAccessStringType =
ConfigurationManager.AppSettings["aspnet_staterKits_TimeTracker_DataAccessLayerType"];
if (String.IsNullOrEmpty(dataAccessStringType)) {
throw (new NullReferenceException("ConnectionString
configuration is missing from you web.config. It should contain
<connectionStrings> <add key=\"aspnet_staterKits_TimeTracker\"
value=\"Server=(local);Integrated
Security=True;Database=Issue_Tracker\" </connectionStrings>"));
}
else {
Type dataAccessType = Type.GetType(dataAccessStringType);
if (dataAccessType == null) {
throw (new NullReferenceException("DataAccessType can not be
found"));
}
Type tp =
Type.GetType("ASPNET.StarterKit.DataAccessLayer.DataAccess");
if (!tp.IsAssignableFrom(dataAccessType)) {
throw (new ArgumentException("DataAccessType does not
inherits from ASPNET.StarterKit.DataAccessLayer.DataAccess "));

}
DataAccess dc =
(DataAccess)Activator.CreateInstance(dataAccessType);
return (dc);
}
}
}
}

============================
DataAcess.cs:

using System;
using System.Configuration;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using ASPNET.StarterKit.BusinessLogicLayer;

namespace ASPNET.StarterKit.DataAccessLayer {
public abstract class DataAccess {
/*** PROPERTIES ***/
protected string ConnectionString {
get {
if
(ConfigurationManager.ConnectionStrings["aspnet_staterKits_TimeTracker"]
== null)
throw (new NullReferenceException("ConnectionString
configuration is missing from you web.config. It should contain
<connectionStrings> <add key=\"aspnet_staterKits_TimeTracker\"
value=\"Server=(local);Integrated
Security=True;Database=Issue_Tracker\" </connectionStrings>"));

string connectionString =
ConfigurationManager.ConnectionStrings["aspnet_staterKits_TimeTracker"].ConnectionString;

if (String.IsNullOrEmpty(connectionString))
throw (new NullReferenceException("ConnectionString
configuration is missing from you web.config. It should contain
<connectionStrings> <add key=\"aspnet_staterKits_TimeTracker\"
value=\"Server=(local);Integrated
Security=True;Database=Issue_Tracker\" </connectionStrings>"));
else
return (connectionString);
}
}

/*** METHODS ***/

//Category
public abstract int CreateNewCategory(Category newCategory);
public abstract bool DeleteCategory(int categoryId);
public abstract List<Category> GetAllCategories();
public abstract Category GetCategoryByCategoryId(int Id);
public abstract List<Category> GetCategoriesByProjectId(int
projectId);
public abstract Category
GetCategoryByCategoryNameandProjectId(string categoryName, int
projectId);
public abstract bool UpdateCategory(Category newCategory);

//TimeEntry
public abstract int CreateNewTimeEntry(TimeEntry newTimeEntry);
public abstract bool DeleteTimeEntry(int timeEntryId);
public abstract List<TimeEntry> GetAllTimeEntries();
public abstract List<TimeEntry> GetTimeEntries(int projectId,
string userName);
public abstract TimeEntry GetTimeEntryById(int timeEntryId);
public abstract List<TimeEntry>
GetTimeEntriesByUserNameAndDates(string userName,

DateTime startingDate, DateTime endDate);
public abstract bool UpdateTimeEntry(TimeEntry timeEntry);

// Project
public abstract bool AddUserToProject(int projectId, string
userName);
public abstract int CreateNewProject(Project newProject);
public abstract bool DeleteProject(int projectID);
public abstract List<Project> GetAllProjects();
public abstract Project GetProjectById(int projectId);
public abstract List<Project> GetProjectsByManagerUserName(string
userName);
public abstract List<string> GetProjectMembers(int Id);
public abstract List<Project> GetProjectsByUserName(string
userName);
public abstract bool RemoveUserFromProject(int projectId, string
userName);
public abstract bool UpdateProject(Project projectToUpdate);

//User report
public abstract List<UserReport> GetUserReportsByProjectId(int
projectId);
public abstract List<UserReport> GetUserReportsByCategoryId(int
categoryId);

// UserTotalDurationReport
public abstract List<UserTotalDurationReport>
GetUserReportsByUserName(string userName);

}//class end
}//namespace




============================
sqldataaccesslayer.cs:

using System;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Web.UI.WebControls;
using ASPNET.StarterKit.BusinessLogicLayer;

namespace ASPNET.StarterKit.DataAccessLayer {
public class SQLDataAccess : DataAccess {
/*** DELEGATE ***/

private delegate void TGenerateListFromReader<T>(SqlDataReader
returnData, ref List<T> tempList);

/***************************** BASE CLASS IMPLEMENTATION
*****************************/

/*** CATEGORY ***/
private const string SP_CATEGORY_CREATE =
"aspnet_starterkits_CreateNewCategory";
private const string SP_CATEGORY_DELETE =
"aspnet_starterkits_DeleteCategory";
private const string SP_CATEGORY_GETALLCATEGORIES =
"aspnet_starterkits_GetAllCategories";
private const string SP_CATEGORY_GETCATEGORYBYPROJECTID =
"aspnet_starterkits_GetCategoriesByProjectId";
private const string SP_CATEGORY_GETCATEGORYBYID =
"aspnet_starterkits_GetCategoryById";
private const string SP_CATEGORY_GETCATEGORYBYNAMEANDPROJECT =
"aspnet_starterkits_GetCategoryByNameAndProjectId";
private const string SP_CATEGORY_UPDATE =
"aspnet_starterkits_UpdateCategories";



public override int CreateNewCategory(Category newCategory) {
if (newCategory == null)
throw (new ArgumentNullException("newCategory"));

SqlCommand sqlCmd = new SqlCommand();

AddParamToSQLCmd(sqlCmd, "@ReturnValue", SqlDbType.Int, 0,
ParameterDirection.ReturnValue, null);
AddParamToSQLCmd(sqlCmd, "@CategoryAbbreviation",
SqlDbType.NText, 255, ParameterDirection.Input,
newCategory.Abbreviation);
AddParamToSQLCmd(sqlCmd, "@CategoryEstimateDuration",
SqlDbType.Decimal, 0, ParameterDirection.Input,
newCategory.EstimateDuration);
AddParamToSQLCmd(sqlCmd, "@CategoryName", SqlDbType.NText, 255,
ParameterDirection.Input, newCategory.Name);
AddParamToSQLCmd(sqlCmd, "@ProjectId", SqlDbType.Int, 0,
ParameterDirection.Input, newCategory.ProjectId);

SetCommandType(sqlCmd, CommandType.StoredProcedure,
SP_CATEGORY_CREATE);
ExecuteScalarCmd(sqlCmd);

return ((int)sqlCmd.Parameters["@ReturnValue"].Value);
}

.... code continues on
============================
 
H

Hans Kesting

In the microsoft starter kit Time Tracker application, the data access
layer code consist of three cs files.

DataAccessHelper.cs
DataAcess.cs
SQLDataAccessLayer.cs

DataAcccessHelper appears to be checking that the correct data type is
used
DataAcess sets an abstract class and methods
SQLDataAccessLayer implements DataAcess

My noob question is why abstract? In Laymans terms please.

Granted, I'm still struggling with OOP concepts, but If you were coding
this application from scratch, and none of this code came from anywhere
else or was expected to be used anywhere would you really need all
three cs files and the inheritance of a baseclass public class
SQLDataAccess : DataAccess ?

Time Tracker can be found here:
http://msdn.microsoft.com/vstudio/express/vwd/starterkit/

If you want to define an OraDataAccess class (to access Oracle) and
still want to be able to use either Ora.. or Sql.. in some generic
class at a higher level, then you need some sort of "common ground".
This can be either an interface (a "contract" that specifies the names
(signatures) of some common methods, WITHOUT any implementation),
or a baseclass that CAN contain some basic/common implementation.
This baseclass can contain "placeholders" for methods whose names are
known but still need to be implemented. These "abstract" methods make
this baseclass also "abstract".

In your case that generic class can now use parameters of type
"DataAccess". You can put in either a SqlDataAccess or OraDataAccess
instance to have it access the correct (type of) database.

So, you don't *need* a baseclass (or an abstract class). But in case
you suspect that you could have a number of similar classes, *then* you
should move that "similar" code to some (possibly abstract) baseclass.

Hans Kesting
 
K

Kevin Spencer

Hi Jason,

This is all about Inheritance, one of the pillars of OOP. The chief purpose
of inheritance is efficiency. It is not efficient to duplicate code. And
many classes may do very similar types of things. Inheritance is also about
code maintainability, ease of use, and extensibility.

Now, inheritance takes several forms in OOP, and they all serve different
purposes. The first would be Interfaces. An Interface is a "contract" that
ensures that any class implementing the Interface implements all the members
of the Interface. The Interface does not define the members themselves, but
defines their programming interface (name, type, parameters, etc). This way,
any client that knows about the Interface can use any class that implements
that Interface. Each class implementing the Interface may use different
implementations of the Interface; that is, the code that is executed may be
completely different, as long as the programming Interface is the same.

The next step above Interface is the Abstract modifier. An abstract class is
a class that may not be used directly, but may be inherited. It contains
both defined and undefined properties and methods. The undefined methods are
declared as "abstract" and do not have any definition code, other than the
signatures of these properties and methods, just like an Interface. Other
properties and methods may be defined, providing a common definition that
may be used by any derived class, or in some cases, overridden in the
derived classes. This is useful when some aspects of a class are
commonly-defined, or may need a common default, but other aspects need to be
explicitly defined for each inherited class.

Finally, there is inheritance of a class that is not abstract. A
non-abstract class defines everything. It can be extended by derived classes
via overriding existing members, or adding new ones. This is useful when the
base class is useful as is, but may need extending for other purposes.

--
HTH,

Kevin Spencer
Microsoft MVP
Chicken Salad Surgery

What You Seek Is What You Get.

In the microsoft starter kit Time Tracker application, the data access
layer code consist of three cs files.

DataAccessHelper.cs
DataAcess.cs
SQLDataAccessLayer.cs

DataAcccessHelper appears to be checking that the correct data type is
used
DataAcess sets an abstract class and methods
SQLDataAccessLayer implements DataAcess


My noob question is why abstract? In Laymans terms please.

Granted, I'm still struggling with OOP concepts, but If you were coding
this application from scratch, and none of this code came from anywhere
else or was expected to be used anywhere would you really need all
three cs files and the inheritance of a baseclass public class
SQLDataAccess : DataAccess ?



Time Tracker can be found here:
http://msdn.microsoft.com/vstudio/express/vwd/starterkit/

The three sources in question:

====================
DataAccesshelper.cs:

using System;
using System.Configuration;

namespace ASPNET.StarterKit.DataAccessLayer {
public class DataAccessHelper {
public static DataAccess GetDataAccess() {
string dataAccessStringType =
ConfigurationManager.AppSettings["aspnet_staterKits_TimeTracker_DataAccessLayerType"];
if (String.IsNullOrEmpty(dataAccessStringType)) {
throw (new NullReferenceException("ConnectionString
configuration is missing from you web.config. It should contain
<connectionStrings> <add key=\"aspnet_staterKits_TimeTracker\"
value=\"Server=(local);Integrated
Security=True;Database=Issue_Tracker\" </connectionStrings>"));
}
else {
Type dataAccessType = Type.GetType(dataAccessStringType);
if (dataAccessType == null) {
throw (new NullReferenceException("DataAccessType can not be
found"));
}
Type tp =
Type.GetType("ASPNET.StarterKit.DataAccessLayer.DataAccess");
if (!tp.IsAssignableFrom(dataAccessType)) {
throw (new ArgumentException("DataAccessType does not
inherits from ASPNET.StarterKit.DataAccessLayer.DataAccess "));

}
DataAccess dc =
(DataAccess)Activator.CreateInstance(dataAccessType);
return (dc);
}
}
}
}

============================
DataAcess.cs:

using System;
using System.Configuration;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using ASPNET.StarterKit.BusinessLogicLayer;

namespace ASPNET.StarterKit.DataAccessLayer {
public abstract class DataAccess {
/*** PROPERTIES ***/
protected string ConnectionString {
get {
if
(ConfigurationManager.ConnectionStrings["aspnet_staterKits_TimeTracker"]
== null)
throw (new NullReferenceException("ConnectionString
configuration is missing from you web.config. It should contain
<connectionStrings> <add key=\"aspnet_staterKits_TimeTracker\"
value=\"Server=(local);Integrated
Security=True;Database=Issue_Tracker\" </connectionStrings>"));

string connectionString =
ConfigurationManager.ConnectionStrings["aspnet_staterKits_TimeTracker"].ConnectionString;

if (String.IsNullOrEmpty(connectionString))
throw (new NullReferenceException("ConnectionString
configuration is missing from you web.config. It should contain
<connectionStrings> <add key=\"aspnet_staterKits_TimeTracker\"
value=\"Server=(local);Integrated
Security=True;Database=Issue_Tracker\" </connectionStrings>"));
else
return (connectionString);
}
}

/*** METHODS ***/

//Category
public abstract int CreateNewCategory(Category newCategory);
public abstract bool DeleteCategory(int categoryId);
public abstract List<Category> GetAllCategories();
public abstract Category GetCategoryByCategoryId(int Id);
public abstract List<Category> GetCategoriesByProjectId(int
projectId);
public abstract Category
GetCategoryByCategoryNameandProjectId(string categoryName, int
projectId);
public abstract bool UpdateCategory(Category newCategory);

//TimeEntry
public abstract int CreateNewTimeEntry(TimeEntry newTimeEntry);
public abstract bool DeleteTimeEntry(int timeEntryId);
public abstract List<TimeEntry> GetAllTimeEntries();
public abstract List<TimeEntry> GetTimeEntries(int projectId,
string userName);
public abstract TimeEntry GetTimeEntryById(int timeEntryId);
public abstract List<TimeEntry>
GetTimeEntriesByUserNameAndDates(string userName,

DateTime startingDate, DateTime endDate);
public abstract bool UpdateTimeEntry(TimeEntry timeEntry);

// Project
public abstract bool AddUserToProject(int projectId, string
userName);
public abstract int CreateNewProject(Project newProject);
public abstract bool DeleteProject(int projectID);
public abstract List<Project> GetAllProjects();
public abstract Project GetProjectById(int projectId);
public abstract List<Project> GetProjectsByManagerUserName(string
userName);
public abstract List<string> GetProjectMembers(int Id);
public abstract List<Project> GetProjectsByUserName(string
userName);
public abstract bool RemoveUserFromProject(int projectId, string
userName);
public abstract bool UpdateProject(Project projectToUpdate);

//User report
public abstract List<UserReport> GetUserReportsByProjectId(int
projectId);
public abstract List<UserReport> GetUserReportsByCategoryId(int
categoryId);

// UserTotalDurationReport
public abstract List<UserTotalDurationReport>
GetUserReportsByUserName(string userName);

}//class end
}//namespace




============================
sqldataaccesslayer.cs:

using System;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Web.UI.WebControls;
using ASPNET.StarterKit.BusinessLogicLayer;

namespace ASPNET.StarterKit.DataAccessLayer {
public class SQLDataAccess : DataAccess {
/*** DELEGATE ***/

private delegate void TGenerateListFromReader<T>(SqlDataReader
returnData, ref List<T> tempList);

/***************************** BASE CLASS IMPLEMENTATION
*****************************/

/*** CATEGORY ***/
private const string SP_CATEGORY_CREATE =
"aspnet_starterkits_CreateNewCategory";
private const string SP_CATEGORY_DELETE =
"aspnet_starterkits_DeleteCategory";
private const string SP_CATEGORY_GETALLCATEGORIES =
"aspnet_starterkits_GetAllCategories";
private const string SP_CATEGORY_GETCATEGORYBYPROJECTID =
"aspnet_starterkits_GetCategoriesByProjectId";
private const string SP_CATEGORY_GETCATEGORYBYID =
"aspnet_starterkits_GetCategoryById";
private const string SP_CATEGORY_GETCATEGORYBYNAMEANDPROJECT =
"aspnet_starterkits_GetCategoryByNameAndProjectId";
private const string SP_CATEGORY_UPDATE =
"aspnet_starterkits_UpdateCategories";



public override int CreateNewCategory(Category newCategory) {
if (newCategory == null)
throw (new ArgumentNullException("newCategory"));

SqlCommand sqlCmd = new SqlCommand();

AddParamToSQLCmd(sqlCmd, "@ReturnValue", SqlDbType.Int, 0,
ParameterDirection.ReturnValue, null);
AddParamToSQLCmd(sqlCmd, "@CategoryAbbreviation",
SqlDbType.NText, 255, ParameterDirection.Input,
newCategory.Abbreviation);
AddParamToSQLCmd(sqlCmd, "@CategoryEstimateDuration",
SqlDbType.Decimal, 0, ParameterDirection.Input,
newCategory.EstimateDuration);
AddParamToSQLCmd(sqlCmd, "@CategoryName", SqlDbType.NText, 255,
ParameterDirection.Input, newCategory.Name);
AddParamToSQLCmd(sqlCmd, "@ProjectId", SqlDbType.Int, 0,
ParameterDirection.Input, newCategory.ProjectId);

SetCommandType(sqlCmd, CommandType.StoredProcedure,
SP_CATEGORY_CREATE);
ExecuteScalarCmd(sqlCmd);

return ((int)sqlCmd.Parameters["@ReturnValue"].Value);
}

... code continues on
============================
 
J

jason

Thanks for that. What is a bit blurry is WHEN it makes sense use an
interface versus an abstract class.

In this article, which I've read 3 times now
http://www.codeproject.com/csharp/AbstractsVSInterfaces.asp

he does a good job of pointing out differences, and I even loaded to
the code .. but what puzzles me a bit is that his example shows them as
almost interchangable.

In laymans terms, can anyone produce a simple, real-world example
(perhaps using the class Animal class dog class cat makenoise()
classes/methods) to demonstrate WHERE it makes sense to use interface
versus abstract and WHY.

Thanks in advances for responses, those did help a lot already!


Kevin said:
Hi Jason,

This is all about Inheritance, one of the pillars of OOP. The chief purpose
of inheritance is efficiency. It is not efficient to duplicate code. And
many classes may do very similar types of things. Inheritance is also about
code maintainability, ease of use, and extensibility.

Now, inheritance takes several forms in OOP, and they all serve different
purposes. The first would be Interfaces. An Interface is a "contract" that
ensures that any class implementing the Interface implements all the members
of the Interface. The Interface does not define the members themselves, but
defines their programming interface (name, type, parameters, etc). This way,
any client that knows about the Interface can use any class that implements
that Interface. Each class implementing the Interface may use different
implementations of the Interface; that is, the code that is executed may be
completely different, as long as the programming Interface is the same.

The next step above Interface is the Abstract modifier. An abstract class is
a class that may not be used directly, but may be inherited. It contains
both defined and undefined properties and methods. The undefined methods are
declared as "abstract" and do not have any definition code, other than the
signatures of these properties and methods, just like an Interface. Other
properties and methods may be defined, providing a common definition that
may be used by any derived class, or in some cases, overridden in the
derived classes. This is useful when some aspects of a class are
commonly-defined, or may need a common default, but other aspects need to be
explicitly defined for each inherited class.

Finally, there is inheritance of a class that is not abstract. A
non-abstract class defines everything. It can be extended by derived classes
via overriding existing members, or adding new ones. This is useful when the
base class is useful as is, but may need extending for other purposes.

--
HTH,

Kevin Spencer
Microsoft MVP
Chicken Salad Surgery

What You Seek Is What You Get.

In the microsoft starter kit Time Tracker application, the data access
layer code consist of three cs files.

DataAccessHelper.cs
DataAcess.cs
SQLDataAccessLayer.cs

DataAcccessHelper appears to be checking that the correct data type is
used
DataAcess sets an abstract class and methods
SQLDataAccessLayer implements DataAcess


My noob question is why abstract? In Laymans terms please.

Granted, I'm still struggling with OOP concepts, but If you were coding
this application from scratch, and none of this code came from anywhere
else or was expected to be used anywhere would you really need all
three cs files and the inheritance of a baseclass public class
SQLDataAccess : DataAccess ?



Time Tracker can be found here:
http://msdn.microsoft.com/vstudio/express/vwd/starterkit/

The three sources in question:

====================
DataAccesshelper.cs:

using System;
using System.Configuration;

namespace ASPNET.StarterKit.DataAccessLayer {
public class DataAccessHelper {
public static DataAccess GetDataAccess() {
string dataAccessStringType =
ConfigurationManager.AppSettings["aspnet_staterKits_TimeTracker_DataAccessLayerType"];
if (String.IsNullOrEmpty(dataAccessStringType)) {
throw (new NullReferenceException("ConnectionString
configuration is missing from you web.config. It should contain
<connectionStrings> <add key=\"aspnet_staterKits_TimeTracker\"
value=\"Server=(local);Integrated
Security=True;Database=Issue_Tracker\" </connectionStrings>"));
}
else {
Type dataAccessType = Type.GetType(dataAccessStringType);
if (dataAccessType == null) {
throw (new NullReferenceException("DataAccessType can not be
found"));
}
Type tp =
Type.GetType("ASPNET.StarterKit.DataAccessLayer.DataAccess");
if (!tp.IsAssignableFrom(dataAccessType)) {
throw (new ArgumentException("DataAccessType does not
inherits from ASPNET.StarterKit.DataAccessLayer.DataAccess "));

}
DataAccess dc =
(DataAccess)Activator.CreateInstance(dataAccessType);
return (dc);
}
}
}
}

============================
DataAcess.cs:

using System;
using System.Configuration;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using ASPNET.StarterKit.BusinessLogicLayer;

namespace ASPNET.StarterKit.DataAccessLayer {
public abstract class DataAccess {
/*** PROPERTIES ***/
protected string ConnectionString {
get {
if
(ConfigurationManager.ConnectionStrings["aspnet_staterKits_TimeTracker"]
== null)
throw (new NullReferenceException("ConnectionString
configuration is missing from you web.config. It should contain
<connectionStrings> <add key=\"aspnet_staterKits_TimeTracker\"
value=\"Server=(local);Integrated
Security=True;Database=Issue_Tracker\" </connectionStrings>"));

string connectionString =
ConfigurationManager.ConnectionStrings["aspnet_staterKits_TimeTracker"].ConnectionString;

if (String.IsNullOrEmpty(connectionString))
throw (new NullReferenceException("ConnectionString
configuration is missing from you web.config. It should contain
<connectionStrings> <add key=\"aspnet_staterKits_TimeTracker\"
value=\"Server=(local);Integrated
Security=True;Database=Issue_Tracker\" </connectionStrings>"));
else
return (connectionString);
}
}

/*** METHODS ***/

//Category
public abstract int CreateNewCategory(Category newCategory);
public abstract bool DeleteCategory(int categoryId);
public abstract List<Category> GetAllCategories();
public abstract Category GetCategoryByCategoryId(int Id);
public abstract List<Category> GetCategoriesByProjectId(int
projectId);
public abstract Category
GetCategoryByCategoryNameandProjectId(string categoryName, int
projectId);
public abstract bool UpdateCategory(Category newCategory);

//TimeEntry
public abstract int CreateNewTimeEntry(TimeEntry newTimeEntry);
public abstract bool DeleteTimeEntry(int timeEntryId);
public abstract List<TimeEntry> GetAllTimeEntries();
public abstract List<TimeEntry> GetTimeEntries(int projectId,
string userName);
public abstract TimeEntry GetTimeEntryById(int timeEntryId);
public abstract List<TimeEntry>
GetTimeEntriesByUserNameAndDates(string userName,

DateTime startingDate, DateTime endDate);
public abstract bool UpdateTimeEntry(TimeEntry timeEntry);

// Project
public abstract bool AddUserToProject(int projectId, string
userName);
public abstract int CreateNewProject(Project newProject);
public abstract bool DeleteProject(int projectID);
public abstract List<Project> GetAllProjects();
public abstract Project GetProjectById(int projectId);
public abstract List<Project> GetProjectsByManagerUserName(string
userName);
public abstract List<string> GetProjectMembers(int Id);
public abstract List<Project> GetProjectsByUserName(string
userName);
public abstract bool RemoveUserFromProject(int projectId, string
userName);
public abstract bool UpdateProject(Project projectToUpdate);

//User report
public abstract List<UserReport> GetUserReportsByProjectId(int
projectId);
public abstract List<UserReport> GetUserReportsByCategoryId(int
categoryId);

// UserTotalDurationReport
public abstract List<UserTotalDurationReport>
GetUserReportsByUserName(string userName);

}//class end
}//namespace




============================
sqldataaccesslayer.cs:

using System;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Web.UI.WebControls;
using ASPNET.StarterKit.BusinessLogicLayer;

namespace ASPNET.StarterKit.DataAccessLayer {
public class SQLDataAccess : DataAccess {
/*** DELEGATE ***/

private delegate void TGenerateListFromReader<T>(SqlDataReader
returnData, ref List<T> tempList);

/***************************** BASE CLASS IMPLEMENTATION
*****************************/

/*** CATEGORY ***/
private const string SP_CATEGORY_CREATE =
"aspnet_starterkits_CreateNewCategory";
private const string SP_CATEGORY_DELETE =
"aspnet_starterkits_DeleteCategory";
private const string SP_CATEGORY_GETALLCATEGORIES =
"aspnet_starterkits_GetAllCategories";
private const string SP_CATEGORY_GETCATEGORYBYPROJECTID =
"aspnet_starterkits_GetCategoriesByProjectId";
private const string SP_CATEGORY_GETCATEGORYBYID =
"aspnet_starterkits_GetCategoryById";
private const string SP_CATEGORY_GETCATEGORYBYNAMEANDPROJECT =
"aspnet_starterkits_GetCategoryByNameAndProjectId";
private const string SP_CATEGORY_UPDATE =
"aspnet_starterkits_UpdateCategories";



public override int CreateNewCategory(Category newCategory) {
if (newCategory == null)
throw (new ArgumentNullException("newCategory"));

SqlCommand sqlCmd = new SqlCommand();

AddParamToSQLCmd(sqlCmd, "@ReturnValue", SqlDbType.Int, 0,
ParameterDirection.ReturnValue, null);
AddParamToSQLCmd(sqlCmd, "@CategoryAbbreviation",
SqlDbType.NText, 255, ParameterDirection.Input,
newCategory.Abbreviation);
AddParamToSQLCmd(sqlCmd, "@CategoryEstimateDuration",
SqlDbType.Decimal, 0, ParameterDirection.Input,
newCategory.EstimateDuration);
AddParamToSQLCmd(sqlCmd, "@CategoryName", SqlDbType.NText, 255,
ParameterDirection.Input, newCategory.Name);
AddParamToSQLCmd(sqlCmd, "@ProjectId", SqlDbType.Int, 0,
ParameterDirection.Input, newCategory.ProjectId);

SetCommandType(sqlCmd, CommandType.StoredProcedure,
SP_CATEGORY_CREATE);
ExecuteScalarCmd(sqlCmd);

return ((int)sqlCmd.Parameters["@ReturnValue"].Value);
}

... code continues on
============================
 
B

Bob Powell [MVP]

An abstract class enables you to enforce some implementation details while
ensuring that the derived class fulfils the rest of the interface contract.
An interface is for when you don't care about implementation details but
must enforce a contract between classes.

Interfaces are also useful for when you don't want to burden the
implementation with a specific inheritance tree. Abstract classes force the
derived class to be a descendent of a specific base but an interface can be
implemented by any class with any base.

--
Bob Powell [MVP]
Visual C#, System.Drawing

Ramuseco Limited .NET consulting
http://www.ramuseco.com

Find great Windows Forms articles in Windows Forms Tips and Tricks
http://www.bobpowell.net/tipstricks.htm

Answer those GDI+ questions with the GDI+ FAQ
http://www.bobpowell.net/faqmain.htm

All new articles provide code in C# and VB.NET.
Subscribe to the RSS feeds provided and never miss a new article.



Thanks for that. What is a bit blurry is WHEN it makes sense use an
interface versus an abstract class.

In this article, which I've read 3 times now
http://www.codeproject.com/csharp/AbstractsVSInterfaces.asp

he does a good job of pointing out differences, and I even loaded to
the code .. but what puzzles me a bit is that his example shows them as
almost interchangable.

In laymans terms, can anyone produce a simple, real-world example
(perhaps using the class Animal class dog class cat makenoise()
classes/methods) to demonstrate WHERE it makes sense to use interface
versus abstract and WHY.

Thanks in advances for responses, those did help a lot already!


Kevin said:
Hi Jason,

This is all about Inheritance, one of the pillars of OOP. The chief
purpose
of inheritance is efficiency. It is not efficient to duplicate code. And
many classes may do very similar types of things. Inheritance is also
about
code maintainability, ease of use, and extensibility.

Now, inheritance takes several forms in OOP, and they all serve different
purposes. The first would be Interfaces. An Interface is a "contract"
that
ensures that any class implementing the Interface implements all the
members
of the Interface. The Interface does not define the members themselves,
but
defines their programming interface (name, type, parameters, etc). This
way,
any client that knows about the Interface can use any class that
implements
that Interface. Each class implementing the Interface may use different
implementations of the Interface; that is, the code that is executed may
be
completely different, as long as the programming Interface is the same.

The next step above Interface is the Abstract modifier. An abstract class
is
a class that may not be used directly, but may be inherited. It contains
both defined and undefined properties and methods. The undefined methods
are
declared as "abstract" and do not have any definition code, other than
the
signatures of these properties and methods, just like an Interface. Other
properties and methods may be defined, providing a common definition that
may be used by any derived class, or in some cases, overridden in the
derived classes. This is useful when some aspects of a class are
commonly-defined, or may need a common default, but other aspects need to
be
explicitly defined for each inherited class.

Finally, there is inheritance of a class that is not abstract. A
non-abstract class defines everything. It can be extended by derived
classes
via overriding existing members, or adding new ones. This is useful when
the
base class is useful as is, but may need extending for other purposes.

--
HTH,

Kevin Spencer
Microsoft MVP
Chicken Salad Surgery

What You Seek Is What You Get.

In the microsoft starter kit Time Tracker application, the data access
layer code consist of three cs files.

DataAccessHelper.cs
DataAcess.cs
SQLDataAccessLayer.cs

DataAcccessHelper appears to be checking that the correct data type is
used
DataAcess sets an abstract class and methods
SQLDataAccessLayer implements DataAcess


My noob question is why abstract? In Laymans terms please.

Granted, I'm still struggling with OOP concepts, but If you were coding
this application from scratch, and none of this code came from anywhere
else or was expected to be used anywhere would you really need all
three cs files and the inheritance of a baseclass public class
SQLDataAccess : DataAccess ?



Time Tracker can be found here:
http://msdn.microsoft.com/vstudio/express/vwd/starterkit/

The three sources in question:

====================
DataAccesshelper.cs:

using System;
using System.Configuration;

namespace ASPNET.StarterKit.DataAccessLayer {
public class DataAccessHelper {
public static DataAccess GetDataAccess() {
string dataAccessStringType =
ConfigurationManager.AppSettings["aspnet_staterKits_TimeTracker_DataAccessLayerType"];
if (String.IsNullOrEmpty(dataAccessStringType)) {
throw (new NullReferenceException("ConnectionString
configuration is missing from you web.config. It should contain
<connectionStrings> <add key=\"aspnet_staterKits_TimeTracker\"
value=\"Server=(local);Integrated
Security=True;Database=Issue_Tracker\" </connectionStrings>"));
}
else {
Type dataAccessType = Type.GetType(dataAccessStringType);
if (dataAccessType == null) {
throw (new NullReferenceException("DataAccessType can not be
found"));
}
Type tp =
Type.GetType("ASPNET.StarterKit.DataAccessLayer.DataAccess");
if (!tp.IsAssignableFrom(dataAccessType)) {
throw (new ArgumentException("DataAccessType does not
inherits from ASPNET.StarterKit.DataAccessLayer.DataAccess "));

}
DataAccess dc =
(DataAccess)Activator.CreateInstance(dataAccessType);
return (dc);
}
}
}
}

============================
DataAcess.cs:

using System;
using System.Configuration;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using ASPNET.StarterKit.BusinessLogicLayer;

namespace ASPNET.StarterKit.DataAccessLayer {
public abstract class DataAccess {
/*** PROPERTIES ***/
protected string ConnectionString {
get {
if
(ConfigurationManager.ConnectionStrings["aspnet_staterKits_TimeTracker"]
== null)
throw (new NullReferenceException("ConnectionString
configuration is missing from you web.config. It should contain
<connectionStrings> <add key=\"aspnet_staterKits_TimeTracker\"
value=\"Server=(local);Integrated
Security=True;Database=Issue_Tracker\" </connectionStrings>"));

string connectionString =
ConfigurationManager.ConnectionStrings["aspnet_staterKits_TimeTracker"].ConnectionString;

if (String.IsNullOrEmpty(connectionString))
throw (new NullReferenceException("ConnectionString
configuration is missing from you web.config. It should contain
<connectionStrings> <add key=\"aspnet_staterKits_TimeTracker\"
value=\"Server=(local);Integrated
Security=True;Database=Issue_Tracker\" </connectionStrings>"));
else
return (connectionString);
}
}

/*** METHODS ***/

//Category
public abstract int CreateNewCategory(Category newCategory);
public abstract bool DeleteCategory(int categoryId);
public abstract List<Category> GetAllCategories();
public abstract Category GetCategoryByCategoryId(int Id);
public abstract List<Category> GetCategoriesByProjectId(int
projectId);
public abstract Category
GetCategoryByCategoryNameandProjectId(string categoryName, int
projectId);
public abstract bool UpdateCategory(Category newCategory);

//TimeEntry
public abstract int CreateNewTimeEntry(TimeEntry newTimeEntry);
public abstract bool DeleteTimeEntry(int timeEntryId);
public abstract List<TimeEntry> GetAllTimeEntries();
public abstract List<TimeEntry> GetTimeEntries(int projectId,
string userName);
public abstract TimeEntry GetTimeEntryById(int timeEntryId);
public abstract List<TimeEntry>
GetTimeEntriesByUserNameAndDates(string userName,

DateTime startingDate, DateTime endDate);
public abstract bool UpdateTimeEntry(TimeEntry timeEntry);

// Project
public abstract bool AddUserToProject(int projectId, string
userName);
public abstract int CreateNewProject(Project newProject);
public abstract bool DeleteProject(int projectID);
public abstract List<Project> GetAllProjects();
public abstract Project GetProjectById(int projectId);
public abstract List<Project> GetProjectsByManagerUserName(string
userName);
public abstract List<string> GetProjectMembers(int Id);
public abstract List<Project> GetProjectsByUserName(string
userName);
public abstract bool RemoveUserFromProject(int projectId, string
userName);
public abstract bool UpdateProject(Project projectToUpdate);

//User report
public abstract List<UserReport> GetUserReportsByProjectId(int
projectId);
public abstract List<UserReport> GetUserReportsByCategoryId(int
categoryId);

// UserTotalDurationReport
public abstract List<UserTotalDurationReport>
GetUserReportsByUserName(string userName);

}//class end
}//namespace




============================
sqldataaccesslayer.cs:

using System;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Web.UI.WebControls;
using ASPNET.StarterKit.BusinessLogicLayer;

namespace ASPNET.StarterKit.DataAccessLayer {
public class SQLDataAccess : DataAccess {
/*** DELEGATE ***/

private delegate void TGenerateListFromReader<T>(SqlDataReader
returnData, ref List<T> tempList);

/***************************** BASE CLASS IMPLEMENTATION
*****************************/

/*** CATEGORY ***/
private const string SP_CATEGORY_CREATE =
"aspnet_starterkits_CreateNewCategory";
private const string SP_CATEGORY_DELETE =
"aspnet_starterkits_DeleteCategory";
private const string SP_CATEGORY_GETALLCATEGORIES =
"aspnet_starterkits_GetAllCategories";
private const string SP_CATEGORY_GETCATEGORYBYPROJECTID =
"aspnet_starterkits_GetCategoriesByProjectId";
private const string SP_CATEGORY_GETCATEGORYBYID =
"aspnet_starterkits_GetCategoryById";
private const string SP_CATEGORY_GETCATEGORYBYNAMEANDPROJECT =
"aspnet_starterkits_GetCategoryByNameAndProjectId";
private const string SP_CATEGORY_UPDATE =
"aspnet_starterkits_UpdateCategories";



public override int CreateNewCategory(Category newCategory) {
if (newCategory == null)
throw (new ArgumentNullException("newCategory"));

SqlCommand sqlCmd = new SqlCommand();

AddParamToSQLCmd(sqlCmd, "@ReturnValue", SqlDbType.Int, 0,
ParameterDirection.ReturnValue, null);
AddParamToSQLCmd(sqlCmd, "@CategoryAbbreviation",
SqlDbType.NText, 255, ParameterDirection.Input,
newCategory.Abbreviation);
AddParamToSQLCmd(sqlCmd, "@CategoryEstimateDuration",
SqlDbType.Decimal, 0, ParameterDirection.Input,
newCategory.EstimateDuration);
AddParamToSQLCmd(sqlCmd, "@CategoryName", SqlDbType.NText, 255,
ParameterDirection.Input, newCategory.Name);
AddParamToSQLCmd(sqlCmd, "@ProjectId", SqlDbType.Int, 0,
ParameterDirection.Input, newCategory.ProjectId);

SetCommandType(sqlCmd, CommandType.StoredProcedure,
SP_CATEGORY_CREATE);
ExecuteScalarCmd(sqlCmd);

return ((int)sqlCmd.Parameters["@ReturnValue"].Value);
}

... code continues on
============================
 
J

jason

This makes sense but something is not adding up.

Looking at CreateNewCategory .. my presumption is one objective is to
keep sqlserver commands and refrences outside to the application data
access code right?

public bool Save() {
DataAccess DALLayer = DataAccessHelper.GetDataAccess();
if (Id <= DefaultValues.GetCategoryIdMinValue()) {
int TempId = DALLayer.CreateNewCategory(this);
if (TempId > DefaultValues.GetCategoryIdMinValue()) {
_Id = TempId;
return true;
}
else
return false;

....

Doing my own test, where say class outide is what migh be
changing...and inside is the application specific code .. Why do I have
to refer to outside in my code to make this work...

runner.cs:

using System;
using System.Collections.Generic;
using System.Text;
using jcp;

namespace jcp
{
class runnerc
{
static void Main(string[] args)
{
inside it = new jcp.outside(); // i thought I could refer
to inside
Console.WriteLine(it.stuff("hello"));
Console.Read();
}
}
}

but I get cannot create an instance of an abstract ??? my code has to
refer to outside? I know I'm missing something here. It seems
backwards. Isn't outside where I would code all my specifc/specialized
code in this simple example. If so, why would i need to refer to in my
application code.
====
inside.cs:

using System;
using System.Collections.Generic;
using System.Text;

namespace jcp
{
public abstract class inside
{
public abstract string stuff(string x);
}

}

=====
outside.cs:

using System;
using System.Collections.Generic;
using System.Text;

namespace jcp
{
public class outside : inside
{
public override string stuff(string x)
{
return x;
}
}

}

====
I suspect this is totally a NOOB complete misconception issue.. just
trying to get it past me.

THANKS.
 
K

Kevin Spencer

Hi Jason,

Examining the characteristics of an abstract class versus an Interface, you
can see that members can be defined in an abstract class. So, if you need a
bunch of classes that share some code, and need to have a common programming
interface, but must perform different operations for other code, the
abstract class would be best, since the shared code can be implemented in
it, whereas an Interface contains no code whatsoever.

--
HTH,

Kevin Spencer
Microsoft MVP
Chicken Salad Surgery

What You Seek Is What You Get.

Thanks for that. What is a bit blurry is WHEN it makes sense use an
interface versus an abstract class.

In this article, which I've read 3 times now
http://www.codeproject.com/csharp/AbstractsVSInterfaces.asp

he does a good job of pointing out differences, and I even loaded to
the code .. but what puzzles me a bit is that his example shows them as
almost interchangable.

In laymans terms, can anyone produce a simple, real-world example
(perhaps using the class Animal class dog class cat makenoise()
classes/methods) to demonstrate WHERE it makes sense to use interface
versus abstract and WHY.

Thanks in advances for responses, those did help a lot already!


Kevin said:
Hi Jason,

This is all about Inheritance, one of the pillars of OOP. The chief
purpose
of inheritance is efficiency. It is not efficient to duplicate code. And
many classes may do very similar types of things. Inheritance is also
about
code maintainability, ease of use, and extensibility.

Now, inheritance takes several forms in OOP, and they all serve different
purposes. The first would be Interfaces. An Interface is a "contract"
that
ensures that any class implementing the Interface implements all the
members
of the Interface. The Interface does not define the members themselves,
but
defines their programming interface (name, type, parameters, etc). This
way,
any client that knows about the Interface can use any class that
implements
that Interface. Each class implementing the Interface may use different
implementations of the Interface; that is, the code that is executed may
be
completely different, as long as the programming Interface is the same.

The next step above Interface is the Abstract modifier. An abstract class
is
a class that may not be used directly, but may be inherited. It contains
both defined and undefined properties and methods. The undefined methods
are
declared as "abstract" and do not have any definition code, other than
the
signatures of these properties and methods, just like an Interface. Other
properties and methods may be defined, providing a common definition that
may be used by any derived class, or in some cases, overridden in the
derived classes. This is useful when some aspects of a class are
commonly-defined, or may need a common default, but other aspects need to
be
explicitly defined for each inherited class.

Finally, there is inheritance of a class that is not abstract. A
non-abstract class defines everything. It can be extended by derived
classes
via overriding existing members, or adding new ones. This is useful when
the
base class is useful as is, but may need extending for other purposes.

--
HTH,

Kevin Spencer
Microsoft MVP
Chicken Salad Surgery

What You Seek Is What You Get.

In the microsoft starter kit Time Tracker application, the data access
layer code consist of three cs files.

DataAccessHelper.cs
DataAcess.cs
SQLDataAccessLayer.cs

DataAcccessHelper appears to be checking that the correct data type is
used
DataAcess sets an abstract class and methods
SQLDataAccessLayer implements DataAcess


My noob question is why abstract? In Laymans terms please.

Granted, I'm still struggling with OOP concepts, but If you were coding
this application from scratch, and none of this code came from anywhere
else or was expected to be used anywhere would you really need all
three cs files and the inheritance of a baseclass public class
SQLDataAccess : DataAccess ?



Time Tracker can be found here:
http://msdn.microsoft.com/vstudio/express/vwd/starterkit/

The three sources in question:

====================
DataAccesshelper.cs:

using System;
using System.Configuration;

namespace ASPNET.StarterKit.DataAccessLayer {
public class DataAccessHelper {
public static DataAccess GetDataAccess() {
string dataAccessStringType =
ConfigurationManager.AppSettings["aspnet_staterKits_TimeTracker_DataAccessLayerType"];
if (String.IsNullOrEmpty(dataAccessStringType)) {
throw (new NullReferenceException("ConnectionString
configuration is missing from you web.config. It should contain
<connectionStrings> <add key=\"aspnet_staterKits_TimeTracker\"
value=\"Server=(local);Integrated
Security=True;Database=Issue_Tracker\" </connectionStrings>"));
}
else {
Type dataAccessType = Type.GetType(dataAccessStringType);
if (dataAccessType == null) {
throw (new NullReferenceException("DataAccessType can not be
found"));
}
Type tp =
Type.GetType("ASPNET.StarterKit.DataAccessLayer.DataAccess");
if (!tp.IsAssignableFrom(dataAccessType)) {
throw (new ArgumentException("DataAccessType does not
inherits from ASPNET.StarterKit.DataAccessLayer.DataAccess "));

}
DataAccess dc =
(DataAccess)Activator.CreateInstance(dataAccessType);
return (dc);
}
}
}
}

============================
DataAcess.cs:

using System;
using System.Configuration;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using ASPNET.StarterKit.BusinessLogicLayer;

namespace ASPNET.StarterKit.DataAccessLayer {
public abstract class DataAccess {
/*** PROPERTIES ***/
protected string ConnectionString {
get {
if
(ConfigurationManager.ConnectionStrings["aspnet_staterKits_TimeTracker"]
== null)
throw (new NullReferenceException("ConnectionString
configuration is missing from you web.config. It should contain
<connectionStrings> <add key=\"aspnet_staterKits_TimeTracker\"
value=\"Server=(local);Integrated
Security=True;Database=Issue_Tracker\" </connectionStrings>"));

string connectionString =
ConfigurationManager.ConnectionStrings["aspnet_staterKits_TimeTracker"].ConnectionString;

if (String.IsNullOrEmpty(connectionString))
throw (new NullReferenceException("ConnectionString
configuration is missing from you web.config. It should contain
<connectionStrings> <add key=\"aspnet_staterKits_TimeTracker\"
value=\"Server=(local);Integrated
Security=True;Database=Issue_Tracker\" </connectionStrings>"));
else
return (connectionString);
}
}

/*** METHODS ***/

//Category
public abstract int CreateNewCategory(Category newCategory);
public abstract bool DeleteCategory(int categoryId);
public abstract List<Category> GetAllCategories();
public abstract Category GetCategoryByCategoryId(int Id);
public abstract List<Category> GetCategoriesByProjectId(int
projectId);
public abstract Category
GetCategoryByCategoryNameandProjectId(string categoryName, int
projectId);
public abstract bool UpdateCategory(Category newCategory);

//TimeEntry
public abstract int CreateNewTimeEntry(TimeEntry newTimeEntry);
public abstract bool DeleteTimeEntry(int timeEntryId);
public abstract List<TimeEntry> GetAllTimeEntries();
public abstract List<TimeEntry> GetTimeEntries(int projectId,
string userName);
public abstract TimeEntry GetTimeEntryById(int timeEntryId);
public abstract List<TimeEntry>
GetTimeEntriesByUserNameAndDates(string userName,

DateTime startingDate, DateTime endDate);
public abstract bool UpdateTimeEntry(TimeEntry timeEntry);

// Project
public abstract bool AddUserToProject(int projectId, string
userName);
public abstract int CreateNewProject(Project newProject);
public abstract bool DeleteProject(int projectID);
public abstract List<Project> GetAllProjects();
public abstract Project GetProjectById(int projectId);
public abstract List<Project> GetProjectsByManagerUserName(string
userName);
public abstract List<string> GetProjectMembers(int Id);
public abstract List<Project> GetProjectsByUserName(string
userName);
public abstract bool RemoveUserFromProject(int projectId, string
userName);
public abstract bool UpdateProject(Project projectToUpdate);

//User report
public abstract List<UserReport> GetUserReportsByProjectId(int
projectId);
public abstract List<UserReport> GetUserReportsByCategoryId(int
categoryId);

// UserTotalDurationReport
public abstract List<UserTotalDurationReport>
GetUserReportsByUserName(string userName);

}//class end
}//namespace




============================
sqldataaccesslayer.cs:

using System;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Web.UI.WebControls;
using ASPNET.StarterKit.BusinessLogicLayer;

namespace ASPNET.StarterKit.DataAccessLayer {
public class SQLDataAccess : DataAccess {
/*** DELEGATE ***/

private delegate void TGenerateListFromReader<T>(SqlDataReader
returnData, ref List<T> tempList);

/***************************** BASE CLASS IMPLEMENTATION
*****************************/

/*** CATEGORY ***/
private const string SP_CATEGORY_CREATE =
"aspnet_starterkits_CreateNewCategory";
private const string SP_CATEGORY_DELETE =
"aspnet_starterkits_DeleteCategory";
private const string SP_CATEGORY_GETALLCATEGORIES =
"aspnet_starterkits_GetAllCategories";
private const string SP_CATEGORY_GETCATEGORYBYPROJECTID =
"aspnet_starterkits_GetCategoriesByProjectId";
private const string SP_CATEGORY_GETCATEGORYBYID =
"aspnet_starterkits_GetCategoryById";
private const string SP_CATEGORY_GETCATEGORYBYNAMEANDPROJECT =
"aspnet_starterkits_GetCategoryByNameAndProjectId";
private const string SP_CATEGORY_UPDATE =
"aspnet_starterkits_UpdateCategories";



public override int CreateNewCategory(Category newCategory) {
if (newCategory == null)
throw (new ArgumentNullException("newCategory"));

SqlCommand sqlCmd = new SqlCommand();

AddParamToSQLCmd(sqlCmd, "@ReturnValue", SqlDbType.Int, 0,
ParameterDirection.ReturnValue, null);
AddParamToSQLCmd(sqlCmd, "@CategoryAbbreviation",
SqlDbType.NText, 255, ParameterDirection.Input,
newCategory.Abbreviation);
AddParamToSQLCmd(sqlCmd, "@CategoryEstimateDuration",
SqlDbType.Decimal, 0, ParameterDirection.Input,
newCategory.EstimateDuration);
AddParamToSQLCmd(sqlCmd, "@CategoryName", SqlDbType.NText, 255,
ParameterDirection.Input, newCategory.Name);
AddParamToSQLCmd(sqlCmd, "@ProjectId", SqlDbType.Int, 0,
ParameterDirection.Input, newCategory.ProjectId);

SetCommandType(sqlCmd, CommandType.StoredProcedure,
SP_CATEGORY_CREATE);
ExecuteScalarCmd(sqlCmd);

return ((int)sqlCmd.Parameters["@ReturnValue"].Value);
}

... code continues on
============================
 
?

=?ISO-8859-1?Q?Arne_Vajh=F8j?=

Thanks for that. What is a bit blurry is WHEN it makes sense use an
interface versus an abstract class.

In this article, which I've read 3 times now
http://www.codeproject.com/csharp/AbstractsVSInterfaces.asp

he does a good job of pointing out differences, and I even loaded to
the code .. but what puzzles me a bit is that his example shows them as
almost interchangable.

In laymans terms, can anyone produce a simple, real-world example
(perhaps using the class Animal class dog class cat makenoise()
classes/methods) to demonstrate WHERE it makes sense to use interface
versus abstract and WHY.

An interface is an abstract class where all methods has
to be abstract.

As a bonus for doing that C# permits you to have a class
implement more than one interface (it can only inherit
from one class).

If whatever you are creating has some implementation code,
then you need to make it an abstract class, because else
it will not compile.

If whatever you are creating does not have any implementation
code, then you should make it an interface and not an abstract
class. Because it clearly states what it is. And because classes
implementing the interface can then inherit from another class.

Arne
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top