首先要明白,virtual不是abstract,被virtual修饰的方法是有具体实现的。具体到楼主的例子,Page类的ProcessRequest是可以直接调用来实现某些功能的。其次,用virtual来修饰方法,就是给子类提供了复写该方法的可能。 假如你自定义了一个类 public class CustomPage : Page{},在该类中,你希望ProcessRequest除了父类原本的功能,还有一些自己的私有实现的话,你就需要复写这个方法 public override void RequestProcess(HttpContext context) { base.RequestProcess(context);//子类私有代码 111 }说白了,被override修饰的方法,既为子类提供了统一的实现,又为子类提供了定制化的可能。 至于这个方法是不是来自接口,其实关系不大。
大家回答那么积极很感谢,根据有些楼主的答案我在本地写了个测试,发现有些不对,代码贴出来供大家指教 public interface IEat { void Eat(); } public class Dog : IEat { public virtual void Eat() { Console.WriteLine("Dog eat"); } } public class WolfDog : Dog { public override void Eat() { Console.WriteLine("WolfDog eat"); } } class Tester { static void Main5(string[] args) { Dog[] dogs = new Dog[2]; dogs[0] = new Dog(); dogs[1] = new WolfDog();
IEat eat; for (int i = 0; i < 2; i++) { eat = dogs[i]; eat.Eat(); } } }上面是标准的方式,下面改变些 先按照 #5 答主的说法试验下 1 删除关键字 virtual 和子类中override关键字运行结果:不是想要的结果 再按照 #8 试验下 显示调用编译不过 #9 的答主的回答然我想到了,前段时间找 "抽象类和接口 他们什么时候使用比较合适的" 时遇到的一个博客 https://blog.csdn.net/wab719591157/article/details/73741919 里面的需求是,在使用何种方式支付前,有个共同的判断(判断金额不能小于0),博主把这个重复判断的功能在先在基类中实现,然后再定义一个抽象函数,让不同支付行为在继承父类后再实现自己不同的方式,当时看后感觉写的很好,又在这里看到#9 答主答案,我把上面需求用答主的想表达的方式,写了一遍 public interface PayWay { bool pay(double money); } public abstract class AbstractPayWay : PayWay { private bool verify(double money) { return money > 0; } public virtual bool pay(double money) { bool verify = this.verify(money); if (!verify) { Console.WriteLine("支付金额验证错误!"); return false; } return true; } //public abstract bool doPay(); } public class WeixinPayWay : AbstractPayWay { public override bool pay(double money) { if (base.pay(money)) { Console.WriteLine("这里无需校验支付金额,直接调用支付方法就行"); Console.WriteLine("微信支付成功"); return true; } return false; } } public class ZhifubaoPayWay : AbstractPayWay { public override bool pay(double money) { if(base.pay(money)) { Console.WriteLine("这里无需校验支付金额,直接调用支付方法就行"); Console.WriteLine("支付宝支付成功"); return true; } return false; } } class Test { static void Main6(string[] args) { AbstractPayWay[] AbsPayWay = { new WeixinPayWay(), new ZhifubaoPayWay() }; PayWay payWayByWinXin= AbsPayWay[0]; payWayByWinXin.pay(111);//微信支付 PayWay payWayByZhiFuBao = AbsPayWay[1]; payWayByZhiFuBao.pay(112);//支付宝支付 } }下面是原博客中用抽象函数写的(我把原Java语言的表达换成了C#) public interface PayWay { bool pay(double money); } public abstract class AbstractPayWay : PayWay { private bool verify(double money) { return money > 0; } public bool pay(double money) { bool verify = this.verify(money); if (!verify) { Console.WriteLine("支付金额验证错误!"); return false; } return this.doPay(); } public abstract bool doPay(); } public class WeixinPayWay : AbstractPayWay { public override bool doPay() { Console.WriteLine("这里无需校验支付金额,直接调用支付方法就行"); Console.WriteLine("微信支付成功"); return false; } } public class ZhifubaoPayWay : AbstractPayWay { public override bool doPay() { Console.WriteLine("这里无需校验支付金额,直接调用支付方法就行"); Console.WriteLine("支付宝支付成功"); return false; } } class Test { static void Main4(string[] args) { AbstractPayWay[] AbsPayWay = { new WeixinPayWay(), new ZhifubaoPayWay() }; for (int i = 0; i < 2; i++) { AbsPayWay[i].doPay(); } } } 那问题来了,这两种方式哪个比较好些,或者实现这种功能还有更好的方式没,大家都说说自己看法吧
这和它是不是实现IHttpHandler接口没关系,虽说这个函数是IHttpHandler里面定义的
没写virtual时,如果派生类中重写了,编译器会提示一个警告,告诉程序员,你可能重写了父类的方法,这会导致隐藏父类的方法。而写父类的程序员并未声明可以重写(Virtual),所以,你可能是取了和父类中的方法同样的一个名字,请检查。==========
最新文章:解读经典《C#高级编程》 第四章之 最全泛型协变逆变解读 https://mp.weixin.qq.com/s/zGWKQNw72tM8GQUGXu18JA
欢迎关注微信公众号 “产品技术知与行” ,解读技术经典书籍(C#,Java,Js),发表技术专题、提供源码下载,打造全面结构化知识库,欢迎对全栈/跨语言技术有兴趣的小伙伴关注。
3楼 NVI模式 确实让我 又涨了见识.
5楼大哥讲的也很好,提问之前也查看virtual的一些特殊用法,https://blog.csdn.net/songsz123/article/details/7369913,
这里面说的无virtual和无override的重写就是大哥想说的不严谨的写法吧.
假如你自定义了一个类 public class CustomPage : Page{},在该类中,你希望ProcessRequest除了父类原本的功能,还有一些自己的私有实现的话,你就需要复写这个方法
public override void RequestProcess(HttpContext context)
{
base.RequestProcess(context);//子类私有代码
111
}说白了,被override修饰的方法,既为子类提供了统一的实现,又为子类提供了定制化的可能。
至于这个方法是不是来自接口,其实关系不大。
{
void Eat();
} public class Dog : IEat
{
public virtual void Eat()
{
Console.WriteLine("Dog eat");
}
} public class WolfDog : Dog
{
public override void Eat()
{
Console.WriteLine("WolfDog eat");
}
} class Tester
{
static void Main5(string[] args)
{
Dog[] dogs = new Dog[2];
dogs[0] = new Dog();
dogs[1] = new WolfDog();
IEat eat;
for (int i = 0; i < 2; i++)
{
eat = dogs[i];
eat.Eat();
}
}
}上面是标准的方式,下面改变些
先按照 #5 答主的说法试验下
1 删除关键字 virtual 和子类中override关键字运行结果:不是想要的结果
再按照 #8 试验下
显示调用编译不过
#9 的答主的回答然我想到了,前段时间找 "抽象类和接口 他们什么时候使用比较合适的" 时遇到的一个博客
https://blog.csdn.net/wab719591157/article/details/73741919
里面的需求是,在使用何种方式支付前,有个共同的判断(判断金额不能小于0),博主把这个重复判断的功能在先在基类中实现,然后再定义一个抽象函数,让不同支付行为在继承父类后再实现自己不同的方式,当时看后感觉写的很好,又在这里看到#9 答主答案,我把上面需求用答主的想表达的方式,写了一遍 public interface PayWay
{
bool pay(double money);
} public abstract class AbstractPayWay : PayWay
{
private bool verify(double money)
{
return money > 0;
}
public virtual bool pay(double money)
{
bool verify = this.verify(money);
if (!verify)
{
Console.WriteLine("支付金额验证错误!");
return false;
}
return true;
} //public abstract bool doPay();
} public class WeixinPayWay : AbstractPayWay
{
public override bool pay(double money)
{
if (base.pay(money))
{
Console.WriteLine("这里无需校验支付金额,直接调用支付方法就行");
Console.WriteLine("微信支付成功");
return true;
}
return false;
}
} public class ZhifubaoPayWay : AbstractPayWay
{
public override bool pay(double money)
{
if(base.pay(money))
{
Console.WriteLine("这里无需校验支付金额,直接调用支付方法就行");
Console.WriteLine("支付宝支付成功");
return true;
}
return false;
}
}
class Test
{
static void Main6(string[] args)
{
AbstractPayWay[] AbsPayWay =
{
new WeixinPayWay(),
new ZhifubaoPayWay()
};
PayWay payWayByWinXin= AbsPayWay[0];
payWayByWinXin.pay(111);//微信支付
PayWay payWayByZhiFuBao = AbsPayWay[1];
payWayByZhiFuBao.pay(112);//支付宝支付
}
}下面是原博客中用抽象函数写的(我把原Java语言的表达换成了C#) public interface PayWay
{
bool pay(double money);
} public abstract class AbstractPayWay : PayWay
{
private bool verify(double money)
{
return money > 0;
}
public bool pay(double money)
{
bool verify = this.verify(money);
if (!verify)
{
Console.WriteLine("支付金额验证错误!");
return false;
}
return this.doPay();
} public abstract bool doPay();
} public class WeixinPayWay : AbstractPayWay
{
public override bool doPay()
{
Console.WriteLine("这里无需校验支付金额,直接调用支付方法就行");
Console.WriteLine("微信支付成功");
return false;
}
} public class ZhifubaoPayWay : AbstractPayWay
{
public override bool doPay()
{
Console.WriteLine("这里无需校验支付金额,直接调用支付方法就行");
Console.WriteLine("支付宝支付成功");
return false;
}
} class Test
{
static void Main4(string[] args)
{
AbstractPayWay[] AbsPayWay =
{
new WeixinPayWay(),
new ZhifubaoPayWay()
};
for (int i = 0; i < 2; i++)
{
AbsPayWay[i].doPay();
}
}
}
那问题来了,这两种方式哪个比较好些,或者实现这种功能还有更好的方式没,大家都说说自己看法吧