复习:关于类的继承和构造函数
要点:
- 基类和派生类
- 防止类被实例化
- 构造函数,尤其是引用基类的构造函数
- 静态方法的新发现
- 相关代码下载
缘由:
经过最近几天的反复思考,今天终于决定,把用户和用户有关的功能从xpnewPage类(这个类是我用来继承System.Web.UI.Page类并派生到后台admin和前台所有.aspx页面的的基类)中分离出来。分离的原因有两个:一方面,是我发觉,放在xpnewPage中用起来不方便,曾经想过单独放到静态类里面,不过很犹豫;另外就是有一次拿我做的用户验证和asp.net 2.0 提供的MemberShip做比较时受到启发,在dot net里面也是分离每次使用都用实例化的。
所以我就下定决心,把用户的功能,从xpnewPage中分离出来。
分离之后,我继续使用基类:前台派生类+后台派生类的模式。
正文:
一、基类和派生类
目前后台的功能基本已经成形了,所以主要是运用在前台用户,后台用户得以后有空的时候再说了。所以,基类是xpnew.User,派生类是xpnew.FrontUser。
在这里面,我准备把前台用户和后台用户的通用的功能,集中起来,放到xpnew.User类中。前台用户的特性放在xpnew.FrontUser类中。比如说在xpnew.User没有限定CookieName的值,但是在xpnew.FrontUser中必须指定CookieName的值。
所以对这种情况,如果从基类和派生类的技术出发那么就应该在派生类中通过重写属性来实现。下面是简略的代码:
{
public class User
{
private string _CookieName;
public User() { }
public virtual string CookieName
{
get
{
return _CookieName;
}
set
{
_CookieName = value;
}
}
}
public class FrontUser:User{
public override string CookieName
{
get
{
base.CookieName = getCookieName();
return base.CookieName;
}
set
{
base.CookieName = value;
}
}
private string getCookieName()
{
string result;
result = "UserCookies";//实际的功能比这个复杂,这里只做简单的表示。
return result;
}
}
}
这里面分别在基类和派生类使用了virtual和override关健字,如果基类没有使用virtural关健字,那么派生类就要使用new关键字来强调,否则vs的编译的时候会给出提示。
二、防止类被实例化
类的实例化,就是以类为模板在内存生成一个具体的对象。例如:
User u = new User();
在这里面User类是前台后台所有用户功能的抽象,虽然它本身可以实现一些功能,但是,功能并不完整,所以有必要防止这个类被实例化。
今天翻看了一下MSDN,总结出来两种不能实例化的情况:
2.1 抽象类和静态类
抽象类是在类前面加上abstract关键字,抽象类的成员全部(或者部分,这个具体的差别我还没来得及实验总结,两个星期以前研究了一下virtual类,好象vrtual类的成员必须全部都是vitural的,抽象类是不是全部都得是抽象的,我记不清没有没实验过了)是抽象的,没有代码实现的,所以这样的类是无法实例化的,假如实例化的话,编译器肯定是无法处理的,所以抽象类是不能实例化的。
静态类是在类前面加上static,静态类的成员全部是静态的,静态类和和静态的方法不需要实例化就能使用。所以静态类也是不能实例化的。
2.2 私有构造函数
根据MSDN所说,我的理解,就是静态类的构造函数被私有化(private)了。同样的情况是,对非静态的类,私有化构造函数之后,这样的类也一样是不能实例化的。
例如,在这里把public User(){} 换成 private User(){},那么就能使用xpnew.User u = new xpnew.User();了。因为在C#中 private关键字限定只能在类内部访问,只能是User.a访问User.b这样。现在跑到类的外面,就是不允许的。
但是,在当前的情况下private User(){},也限定了FrontUser的访问,基类的private成员连派生类也不能访问,就好像说爸爸有个盒子,连儿子也不能动,不知道里面有什么东西。程序运行的时候,提示:“xpnew.User.User()”不可访问,因为它受保护级别限制。
{
public class User
{
private User()
{ }
}
public class FrontUser:User
{
public FrontUser()
{ }
}
}
C#的原理是,每个例在实例化的时候,会运行构造函数,而且一个类的构造函数被调用的时候,也会自动调用基类的构造函数,上面的代码和下面是等效的:
实际运行的过程也是先运行User()再运行FrontUser()。虽然在代码上没有表现出来,但是C#内在的运行机制却会自动完成这个步骤。
对于上面的情况解决办法是更换private为protected,
三、构造函数,除了默认的构造函数之外
上面已经提到了一部分构造函数的内容。下面说一说其它几种情况。
3.1 创建对象的时候一定要用构造函数么?
答案是否定的。有的对象不能使用构造函数,或者有类本身没有构造函数,所以,有的对象创建的过程中必须是通过其它的类、对象、方法创建的。这方面的例子,以后我再慢慢收集整理。
还有时候,获取对象有很多种办法,不必非得使用构造函数。例如下面:
HttpCookie yourcookie = new HttpCookie();
HttpCookie mycookie = HttpContent.Current.Request.Cookies["UserName"];
3.2 构造函数的多样性(暂用这个词)
一类可以有多个重载的构造函数,也可以灵活多样的继承基类的构选函数,下面的代码给出了一部分情况:
第二种是最接我开始时构想的做法,印象中我最初学习C#的书本上有类似的用法。但是调试不成功,改来改去,变成了第四种的样子。以后有机会翻翻书再研究出一种最完美的形式吧。
四、静态方法的新发现
其实我原始的想法是这样的:
public FrontUser() : base(getUserCookie()){}
其中getUserCookie()(稍后有这个代码的最终版本),是通过web.config获取一个cookies的名称。
总体上而言,就是User类里没有具体的cookies检查,因为User类都不知道cookies的名称,怎么能检查呢?要检查的话,也得先设置CookieName属性才行。到了FrontUser类这里,在实例化的时候,就先指定CookieName,一气呵成。然后就能做在线检查、cookie合法检查等操作了。
但是这样的代码却是行不通的。提示的意思说getUserCookie()需要实例化才能使用。可是在构造函数这个地方,连FrontUser()都没有运行(基类的构造函数运行),哪还有它的机会?但是提示中也提到,出现这种情况的原因是这个getUserCookie()不是静态的方法, 所以解决的办法,就是给getUserCookie()加上static关键字。
{
private string _CookieName;
public string CookieName
{
get { return _CookieName; }
set { _CookieName = value; }
}
protected User()
{
}
protected User(string cookiename)
{
CookieName = cookiename;
}
}
public class FrontUser:User
{
public FrontUser() : this(getCookieName()) { }
public FrontUser(string cookiename) : base(cookiename) { }
public static string getCookieName(){
//实际代码比较复杂,这里用简略的方式给出
return "UserCookie";
}
}
后记:
做到这里,就完全实现了通过重载构造函数,初始化派生类这样很拐弯的想法。最初的设想,总算是实现了。于是就上来写一篇博客。可是我却高兴不起来,我感觉样的代码有点别扭。尤其是FrontUser这是一个需要实例化的类,里面却使用了一个静态的方法。而且,我在写这篇博客的时候发现,其实还不如直接使用最简单的方式使用构造函数,然后设置User.CookieName属性了:
{
private string _CookieName;
public string CookieName
{
get { return _CookieName; }
set { _CookieName = value; }
}
protected User()
{
}
}
public class FrontUser:User
{
public FrontUser()
{
CookieName = getCookieName();
}
public string getCookieName(){
//实际代码比较复杂,这里用简略的方式给出
return "UserCookie";
}
}
想想这样七扭八歪的,最终回到了一个简单的办法上,有点可笑,收获就是复习了一些书本上的基本知识了。
另外,我在后面,把相关的三个文件传上来,里面还有一个文本文件的说明。
漂泊是无尽的轮回。