Python3 与 C# 面向对象之~继承与多态
文章汇总:https://www.cnblogs.com/dotnetcrazy/p/9160514.html
目录:
正文:
代码裤子:https://github.com/lotapp/BaseCode
在线编程:https://mybinder.org/v2/gh/lotapp/BaseCode/master
在线预览:http://github.lesschina.com/python/base/oop/2.继承与多态.html
2.继承
2.1.单继承
在OOP中,当我们定义一个Class的时候,可以从某个现有的Class继承
新的Class称为子类,而被继承的class称为 基类 或者 父类
Python的继承格式 ==> xxx(base_class)
小明兴高采烈的听着老师开新课,不一会就看见了一个演示Demo:
class Animal(object): def eat(self): print("动物会吃") class Cat(Animal): # 注意一下Python的继承格式 pass class Dog(Animal): pass def main(): cat = Cat() dog = Dog() cat.eat() dog.eat() if __name__ == "__main__": main()
动物会吃 动物会吃
当听到老师说:“ 私有的属性方法 不会被子类继承 ”的时候,小明心里一颤,联想到之前讲的 类属性、 实例属性、 实例方法、 类方法、 静态方法,于是赶紧写个Demo验证一下:
class Animal(object): # 类属性 name = '动物' def __init__(self): # 实例属性 self.age = 1 def __bug(self): """实例私有方法""" print("我是动物类身上的私有方法:bug") def eat(self): """实例方法""" print("我是实例方法,动物会吃哦~") @classmethod def call(cls): """类方法""" print("我是类方法,动物会叫哦") @staticmethod def play(): """静态方法""" print("我是静态方法,动物会玩耍哦") class Dog(Animal): pass def main(): dog = Dog() # 实例属性 print(dog.age) # 实例方法 dog.eat() # 类属性 print(dog.name) # 类方法 dog.call() Dog.call() Animal.call() # 静态方法 dog.play() Dog.play() Animal.play() if __name__ == '__main__': main()
1 我是实例方法,动物会吃哦~ 动物 我是类方法,动物会叫哦 我是类方法,动物会叫哦 我是类方法,动物会叫哦 我是静态方法,动物会玩耍哦 我是静态方法,动物会玩耍哦 我是静态方法,动物会玩耍哦
来张图就懂了,不是 私有的 都能访问:
这时候,小明老高兴了,单回头一想 ==> 不科学啊,dog应该有其对应的方法吧,C#有 虚方法重写,Python怎么搞?在 子类里面又 怎么调用父类方法呢?
对于小明的提示老师很高兴,于是点名小潘来写一个子类调用父类的demo(老师昨天从窗户里看见小潘有预习):
# 调用父类的方法 class Father(object): def eat(self): print("文雅的吃饭") class Son(Father): def eat(self): # 调用父类方法第1种(super().方法) super().eat() class GrandSon(Son): def eat(self): # 调用父类方法第2种(记得传self) Son.eat(self) def main(): xiaoming = Son() xiaoming.eat() xiaoli = GrandSon() xiaoli.eat() if __name__ == '__main__': main()
文雅的吃饭 文雅的吃饭
一般我们使用 super().方法
来调用父类方法
第二种方法 类名.方法(self)
千万别忘记传self哦
对了,C#是用base关键词,别搞混了
小明这时候可不高兴了,风头怎么能被小潘全部抢走呢,赶紧问问旁边同样预习的伟哥
不一会儿淡定的发了份重写父类方法的demo给老师:
# 重写父类方法==>子类和父类有同名方法 class Father(object): def __init__(self, name): self.name = name def eat(self): print("%s喜欢文雅的吃饭" % self.name) class Son(Father): def __init__(self, name): super().__init__(name) def eat(self): print("%s喜欢大口吃饭大口喝酒" % self.name) def main(): xiaoming = Father("小明") xiaoming.eat() xiaopan = Son("小潘") xiaopan.eat() if __name__ == "__main__": main()
小明喜欢文雅的吃饭 小潘喜欢大口吃饭大口喝酒
老师半喜半忧的说道:“小明同学啊,你也老大不小了,怎么跟孩子一样啊?案例不错,但是怎么能人身攻击人家小潘了?”
当子类和父类都存在相同的 eat()
方法时,我们说,子类的 eat()
覆盖了父类的 eat()
在代码运行的时候,总是会调用子类的 eat()
这样,我们就获得了继承的另一个好处: 多态
2.2.多继承
在讲 多态
之前,我们先引入一下Python的 多继承 对,你没有听错
Java、C#都是单继承,多实现。Python和C++一样,可以多继承,先不要吐槽, 规范使用其实很方便的
来个案例看看:
# 多继承引入 class Father(object): def eat(self): print("文雅的吃饭") class Mom(object): def run(self): print("小碎步") class Son(Father, Mom): pass def main(): son = Son() son.eat() son.run() if __name__ == '__main__': main()
文雅的吃饭 小碎步
继承可以把父类的所有功能都直接拿过来,这样就不必重0开始写代码,子类只需要新增自己特有的方法,也可以把父类不适合的方法覆盖重写
注意一个情况,如果父类里面有同名方法咋办了?到底调哪个呢?
使用 子类名.__mro__
可以看在调方法的时候搜索顺序
一般同名方法都是 先看自己有没有,然后看继承顺序,比如这边 先看Mom再看Father
# 如果父类里面有同名方法怎么知道调哪个? class Father(object): def eat(self): print("文雅的吃饭") class Mom(object): def eat(self): print("开心的吃饭") class Son(Mom, Father): pass def main(): son = Son() son.eat() print(Son.__mro__) # 一般同名方法都是先看自己有没有,然后看继承顺序,比如这边先看Mom再看Father if __name__ == '__main__': main()
开心的吃饭 (<class '__main__.Son'>, <class '__main__.Mom'>, <class '__main__.Father'>, <class 'object'>)
Python的多继承最好是当C#或者Java里面的接口使用,这样结构不会混乱( 特殊情况除外)
来个例子:
class Animal(object): pass class Flyable(object): """飞的方法""" pass class Runable(object): """跑的方法""" pass class Dog(Animal, Runable): pass class Cat(Animal, Runable): pass class Bird(Animal, Flyable): pass class Dack(Animal, Runable, Flyable): """鸭子会飞也会跑""" pass
和C#一样,Python的 父类构造函数不会被继承
其实从资源角度也不应该被继承,如果有1w个子类,那每个子类里面都有一个父类方法,想想这是多么浪费的一件事情?
2.3.C#继承
下课后,小明认真思考总结,然后对照Python写下了C#版的继承:
定义一个人类
public class Person { public string Name { get; set; } public ushort Age { get; set; } public Person(string name, ushort age) { this.Name = name; this.Age = age; } public void Hi()//People { Console.WriteLine("Name: " + this.Name + " Age: " + this.Age); } public virtual void Show()//People { Console.WriteLine("Name: " + this.Name + " Age: " + this.Age); } }
定义一个学生类
public class Student : Person { #region 属性 /// <summary> /// 学校 /// </summary> public string School { get; set; } /// <summary> /// 班级 /// </summary> public string StrClass { get; set; } /// <summary> /// 学号 /// </summary> public string StrNum { get; set; } #endregion #region 构造函数 /// <summary> /// 调用父类构造函数 /// </summary> /// <param name="name"></param> /// <param name="age"></param> public Student(string name, ushort age) : base(name, age) { } public Student(string name, ushort age, string school, string strClass, string strNum) : this(name, age) { this.School = school; this.StrClass = strClass; this.StrNum = strNum; } #endregion /// <summary> /// new-隐藏 /// </summary> public new void Hi()//Student { Console.WriteLine("Name: " + this.Name + " Age: " + this.Age + " School: " + this.School + " strClass: " + this.StrClass + " strNum: " + this.StrNum); } /// <summary> /// override-覆盖 /// </summary> public override void Show()//Student { Console.WriteLine("Name: " + this.Name + " Age: " + this.Age + " School: " + this.School + " strClass: " + this.StrClass + " strNum: " + this.StrNum); } }
调用一下:
Person p = new Student("app", 10, "北京大学", "001", "01001"); p.Hi(); p.Show(); Console.WriteLine(); Student s = p as Student; s.Hi(); s.Show();
结果:
Name: app Age: 10
Name: app Age: 10 School: 北京大学 strClass: 001 strNum: 01001
Name: app Age: 10 School: 北京大学 strClass: 001 strNum: 01001
Name: app Age: 10 School: 北京大学 strClass: 001 strNum: 01001
2.4C#接口的多实现
定义两个接口:
public interface IRun { //什么都不用加 void Run(); } public interface IEat { void Eat(); }
定义一个Dog类来实现两个接口,这样dog就有了run和eat的方法了
var dog = new Dog(); dog.Eat(); dog.Run();
结果:
狗狗吃
狗狗跑
3 多态
3.1.Python
说多态之前说说类型判断,以前我们用 type()
or isinstance()
判断一个变量和另一个变量是否是同一个类型==> type(a)==type(b)
判断一个变量是否是某个类型==> type(a)==A
or isinstance(a,A)
# 判断一个变量是否是某个类型 ==> isinstance() or type class Animal(object): pass class Dog(Animal): pass def main(): dog = Dog() dog2 = Dog() print(type(dog) == Dog) print(type(dog) == type(dog2)) print(type(dog)) print(isinstance(dog, Dog)) print(isinstance(dog, Animal)) # arg 2 must be a type or tuple # print(isinstance(dog, dog2)) if __name__ == '__main__': main()
True True <class '__main__.Dog'> True True
小明老高兴了,终于讲解多态了,不禁问道:“ 多态的好处是啥?”
小潘瞥了一眼小明~“废话,肯定为了 屏蔽子类差异用的啊,像简单工厂不就干的这个事?"
小明楞了楞,眼巴巴的看着老师继续讲课。
设计模式我们会找个专题讲讲,现在给你们说的是Python的基础。
Python是动态语言的“ 鸭子类型”,它并不要求严格的继承体系。
一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子(最后会贴一个案例)
C#实现多态有很多方式,比如虚方法,比如抽象类,比如接口等等...
小明迷迷糊糊的问道:“那 Python怎么实现多态呢?”
老师看了一眼打断他讲课的小明,然后继续说道~来个简单案例:
class People(object): def eat(self): print("人类会吃饭") class Father(object): def eat(self): print("优雅的吃饭") class Teacher(object): def eat(self): print("赶时间的吃饭") # C# 或者 Java里面 写成 eat(People obj) def eat(obj): obj.eat() def main(): teacher = Teacher() father = Father() eat(teacher) eat(father) if __name__ == '__main__': main()
赶时间的吃饭 优雅的吃饭
多态的好处在于,如果这时候我再来个Son子类,有eat()方法编写正确,不用管原来的代码是如何调用的
这次小明懂了,为了装一下,说道:”老师老师,我记得C# 或者 Java里面是写成 eat(People obj) 的吧?“
老师欣慰的笑了一下,说道:”记得刚才说的 填鸭式
吗?Python这么写有个好处哦,我们来看个案例,然后你自己总结“
class People(object): def eat(self): print("人类会吃饭") class Father(object): def eat(self): print("优雅的吃饭") class Teacher(object): def eat(self): print("赶时间的吃饭") class Dog(object): def eat(self): print("舔着吃") def eat(obj): obj.eat() def main(): teacher = Teacher() father = Father() eat(teacher) eat(father) # 我们添加一个不是People子类的Dog类,只要有eat方法,参数一样就可以直接调 dog = Dog() eat(dog) if __name__ == '__main__': main()
赶时间的吃饭 优雅的吃饭 舔着吃
小明突然大声说道:”老师老师,我知道了,Python这是吧类的继承和接口继承融合起来了啊,实现多态就相当于C#里面的接口实现多态啊!!!“
老师点评道:”你姑且可以这么理解,这些我们后面还会继续说的,这种填鸭式的手段刚开始的确会有点不方便,用着用着你就会觉得挺方便的“
小明认真思考总结,然后对照Python和小潘一起写下了 C#版的多态:
3.2.C#虚方法实现多态
定义一个人类:
public class Person { #region 字段+属性 /// <summary> /// 姓名 /// </summary> private string _name; public string Name { get { return _name; } set { _name = value; } } /// <summary> /// 性别 /// </summary> private bool _gender; public bool Gender { get { return _gender; } set { _gender = value; } } /// <summary> /// 年龄 /// </summary> public short Age { get; set; } #endregion #region 构造函数 public Person() { } public Person(string name, bool gender) { this.Name = name; this.Gender = gender; } public Person(string name, bool gender, short age) : this(name, gender) { this.Age = age; } #endregion #region 方法 /// <summary> /// 打招呼 /// </summary> public virtual void SaiHi() { Console.WriteLine("我是一个人类!"); } #endregion }
定义一个女孩类:
public class Gril : Person { #region 构造函数 public Gril() { } public Gril(string name, bool gender) : base(name, gender) { } public Gril(string name, bool gender, short age) : base(name, gender, age) { } #endregion /// <summary> /// 重写父类方法 /// </summary> public override void SaiHi() { string genderStr = Gender == true ? "男孩" : "女孩"; Console.WriteLine($"你好,我叫{Name},今年{Age}岁了,我是一个腼腆的小{genderStr}"); } }
定义一个男孩类:
public class Boy : Person { #region 构造函数 public Boy() { } public Boy(string name, bool gender) : base(name, gender) { } public Boy(string name, bool gender, short age) : base(name, gender, age) { } #endregion //public void SaiHi() public override void SaiHi() { string genderStr = Gender == true ? "男孩" : "女孩"; Console.WriteLine($"你好,我叫{Name},今年{Age}岁了,我是一个腼腆的小{genderStr}"); } }
调用:
static void Main(string[] args) { Person[] persons = { new Person(), new Boy("铁锅", true, 13), new Gril("妞妞", false, 22) }; foreach (var item in persons) { //看看item里面到底放的是什么 Console.WriteLine(item.ToString()); item.SaiHi(); Console.WriteLine(); } }
结果:
Polymorphism1.Person
我是一个人类!
Polymorphism1.Boy
你好,我叫铁锅,今年13岁了,我是一个腼腆的小男孩
Polymorphism1.Gril
你好,我叫妞妞,今年22岁了,我是一个腼腆的小女孩
3.3.C#抽象类实现多态
定义一个动物类:
public abstract class Animal { /// <summary> /// 抽象类中可以有正常的方法 /// </summary> public void Action() { Console.WriteLine("动物可以动"); } /// <summary> /// 抽象方法必须在抽象类中 /// </summary> public abstract void Call(); }
定义一个猫科动物类(子类必须实现父类抽象方法,如果不实现,那么该类也必须是抽象类)
/// <summary> /// 猫科动物---子类必须实现父类抽象方法,如果不实现,那么该类也必须是抽象类 /// </summary> public abstract class Feline : Animal { }
定义一个猫类
public class Cat : Feline { /// <summary> /// 子类必须实现父类抽象方法,如果不实现,那么该类也必须是抽象类 /// </summary> public override void Call() { Console.WriteLine("喵喵叫~~~"); } }
定义一个狗类
public class Dog : Animal { /// <summary> /// 子类必须实现抽象类中的抽象方法 /// </summary> public override void Call() { Console.WriteLine("汪汪叫~~~"); } }
调用:
Animal[] animals = { new Dog(), new Cat() }; foreach (var item in animals) { item.Call(); }
结果:
汪汪叫~~~
喵喵叫~~~
3.4.C#接口实现多态
定义一个跑的接口:
public interface IRun { /// <summary> /// 接口中可以声明属性,方法,索引器等 /// </summary> //string Name { get; set; } void Runing(); }
定义一个猫类:
public class Cat : IRun { public void Runing() { Console.WriteLine("飞快的跑着上树"); } }
定义一个学生类:
public class Student : IRun { public void Runing() { Console.WriteLine("飞快的跑着去上课"); } }
调用:
IRun[] objs = { new Student(), new Cat() }; foreach (var item in objs) { item.Runing(); }
结果:
飞快的跑着去上课
飞快的跑着上树
Python3 与 C# 面向对象之~封装
文章汇总:https://www.cnblogs.com/dotnetcrazy/p/9160514.html
目录:
正文:
最新彩版:https://www.cnblogs.com/dotnetcrazy/p/9202988.html
在线编程:https://mybinder.org/v2/gh/lotapp/BaseCode/master
在线预览:http://github.lesschina.com/python/base/oop/1.封装.html
这次尽量用故事模式来讲知识,上次刚说美化,这次算是第一篇了。步入正题:
1.定义一个类
类的组成:类名、属性(没有字段)、方法
1.1创建一个类
# 类名首字母大写 class Student(object): """创建一个学生类""" # 没有属性定义,直接使用即可 # 定义一个方法,方法里面必须有self(相当于C#的this) def show(self): print("name:%s age:%d"%(self.name,self.age))
# 实例化一个张三 zhangsan=Student() # 给name,age属性赋值 zhangsan.name="张三" zhangsan.age=22 # 调用show方法 zhangsan.show()
name:张三 age:22
# 打印一下类和类的实例 print(Student) print(zhangsan) #张三实例的内存地址:0x7fb6e8502d30
<class '__main__.Student'> <__main__.Student object at 0x7fe961195b70>
和静态语言不同,Python允许对实例变量绑定任何数据 ==> 对于两个实例变量,虽然它们都是同一个类的不同实例,但拥有的变量名称可能都不同
说的比较抽象,举个例子就明了了:
xiaoming=Student("小明",22) xiaoming.mmd="mmd" print(xiaoming.mmd) # 小明和小潘都是Student类,但是小明有的mmd属性,小潘却没有 xiaopan=Student("小潘",22) print(xiaopan.mmd)
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-4-500940527165> in <module>() ----> 1xiaoming=Student("小明",22) 2 xiaoming.mmd="mmd" 3 print(xiaoming.mmd) 4 5 # 小明和小潘都是Student类,但是小明有的mmd属性,小潘却没有 TypeError: object() takes no parameters
1.2使用__init__初始化赋值
创建对象后,python解释器默认调用__init__方法,对必要字段进行初始化赋值
需要注意的是:__init__并不是C#中的构造函数,__new__ (后面会说) + __init__ 等价于构造函数
第一个参数和类的其他方法一样,都是self(相当于C#里面的this,表示创建的实例本身)调用的时候直接忽略它
class Student(object): # 初始化赋值 def __init__(self,name,age): self.name=name self.age=age def show(self): print("name:%s age:%d"%(self.name,self.age))
# 有了__init__方法,在创建实例的时候,就不能传入空的参数了 lisi=Student()
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-6-1ba88e24910b> in <module>() 1 # 有了__init__方法,在创建实例的时候,就不能传入空的参数了 ----> 2lisi=Student() TypeError: __init__() missing 2 required positional arguments: 'name' and 'age'
# 创建一个正确的实例 xiaowang=Student("小王",22) xiaowang.show()
name:小王 age:22
1.3使用魔法方法__str__
在print(类名)的时候自定义输出
这个有点像C#类里面重写ToString,eg:
public override string ToString() { return "Name:" + this.Name + " Age:" + this.Age; }
# Python的__str__()方法 class Student(object): def __init__(self, name, age): self.name = name self.age = age # self别忘记写了,return也别忘了 def __str__(self): return "姓名:%s,年龄:%s" % (self.name, self.age)
lisi = Student("李四", 22) print(lisi) #现在打印就是你DIV的输出了
姓名:李四,年龄:22
1.4 私有属性、方法
C#、Java里面都是有访问修饰符的,Python呢?
Python规定,如果以双下划线__开头的属性或者方法就是私有的
变量名类似xxx的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量。特殊变量是可以直接访问的,不是private变量
在说私有属性前,我们来个案例说说属性不私有的弊端,eg:
小明同学学了点C#,然后学习了上面的知识,心想 ~ Python这么搞安全性呢?不行,我得构造构造,于是有了下面的代码:
class Student(object): def __init__(self, name, age): self.name = name self.age = age def get_name(self): return self.name def set_name(self, name): self.name = name def get_age(self): return self.age def set_age(self, age): if age > 0: self.age = age else: print("age must > 0") def show(self): print("name:%s,age:%d" % (self.name, self.age))
小明心想,想要修改age属性,你通过set_age我就可以判断了哇,还是本宝宝聪明
这时候小潘过来了,淡淡的一笑,看我怎么破了你 ~ 看代码:
zhangsan = Student("张三", -20) zhangsan.show() # name:张三,age:-20 zhangsan.age = -1 # set_age方法形同虚设,我完全可以直接访问字段了 zhangsan.show() # name:张三,age:-1
name:张三,age:-20 name:张三,age:-1
小潘傲气的说道~大叔,给你脸呢。我就是不去访问你设定的方法怎么滴呢?
小明急的啊,赶紧去找伟哥求经。不一会,傲气的贴出自己的New Code,心想着我私有属性都用上了还怕个毛毛:
class Student(object): def __init__(self, name, age): self.__name = name # 一般需要用到的属性都直接放在__init__里面了 # self.__age = age self.set_age(age) def get_name(self): return self.__name def set_name(self, name): self.__name = name def get_age(self): return self.__age def set_age(self, age): if age > 0: self.__age = age else: print("age must > 0") def show(self): print("name:%s,age:%s" % (self.__name, self.__age))
小潘冷笑道~呵呵,然后使用了上次的绝招:
zhangsan = Student("张三", -20) zhangsan.__age = -1 # 同样的代码,只是属性前面加了下划线 zhangsan.show()
age must > 0
--------------------------------------------------------------------------- AttributeError Traceback (most recent call last) <ipython-input-13-82c41ff46846> in <module>() 1 zhangsan = Student("张三", -20) 2 zhangsan.__age = -1 # 同样的代码,只是属性前面加了下划线 ----> 3zhangsan.show() <ipython-input-12-1dec32486a19> in show(self) 22 23 def show(self): ---> 24print("name:%s,age:%s" % (self.__name, self.__age)) AttributeError: 'Student' object has no attribute '_Student__age'
这次小潘同志傻眼了,完全不能访问了啊?不行,怎么能被小明大叔笑话呢?
于是上网翻资料,国内不行就国外,外文不好就翻译,终于找到一个新破解方式:
双下划线开头的实例变量不能直接访问,是因为Python解释器对外把__age变量改成了_Studentage,所以,仍然可以通过**_Studentage**来访问:
# 搞事情 zhangsan._Student__age = -1 zhangsan.show()
name:张三,age:-1
建议你不要这么干,不同版本的Python解释器可能会把__age改成不同的变量名
有些时候,你会看到以一个下划线开头的实例变量名,比如_age这样的实例变量,外部是可以访问的。
但是,请把它视为私有变量,不要随意访问(Python很多东西全凭自觉~捂脸@_@)
小潘终于长叹一口气,然后还不忘取笑小明同学~你这属性搞的,真麻烦,总是通过方法调用,太累了 <_> 鄙视!
这可把小明急的啊,学习的积极性都没有了,吃了碗牛肉面就去伟哥那边好好取经了~
# 私有方法一笔带过 class Student(object): """私有方法""" def __go_home(self): pass zhangsan = Student() zhangsan.__go_home() # 访问不到
--------------------------------------------------------------------------- AttributeError Traceback (most recent call last) <ipython-input-15-45c76191b808> in <module>() 7 8 zhangsan = Student() ----> 9zhangsan.__go_home() # 访问不到 AttributeError: 'Student' object has no attribute '__go_home'
1.5 装饰器,让方法像属性那样便利
Python内置的@property
装饰器就是负责把一个方法变成属性调用的,来个例子
class Student(object): def __init__(self, name, age): # 一般需要用到的属性都直接放在__init__里面了 self.name = name self.age = age @property def name(self): return self.__name @name.setter def name(self, name): self.__name = name @property def age(self): return self.__age @age.setter def age(self, age): if age > 0: self.__age = age else: print("age must > 0") def show(self): print("name:%s,age:%s" % (self.name, self.age))
xiaoming = Student("小明", 22) xiaoming.name = "小潘" xiaoming.age = -2 xiaoming.show()
age must > 0 name:小潘,age:22
把一个getter方法变成属性,只需要加上@property
就可以了
@方法名.setter
,负责把一个setter方法变成属性赋值
当然了,如果只想读 ==> 就只打上@property
标签
小明同学高兴坏了,赶紧大吃了一顿~
1.6 __del__ and __new__
创建对象后,python解释器默认调用__init__() 方法
当删除一个对象时,python解释器也会默认调用__del__() 方法(有点析构函数的味道)
当有1个变量保存了对象的引用时,此对象的引用计数就会加1
当使用del删除变量指向的对象时,如果对象的引用计数不为1,那么每次删除计数减1,当计数为1的时候再调del就真把对象删了
这个可以结合我之前说过的链接来理解:于链接文件的探讨
看着老师夸夸其谈,小明愣了楞,摸摸肚子想到,真BB,我先搞个例子练练:
# 定义一个临时类 class Temp(object): def __del__(self): print("你被干掉了")
验证方面用编辑器比较合适,交互模式下可能不是真正的结果
# 对象被s1和s2引用 s1 = Temp() s2 = s1 del s1 # 只删除s1,新创建的对象并没有被删除 print("-" * 10)
输出:(最后的被干掉是程序退出了)
# ----------
# 你被干掉了
如果用链接来解释就是这样的:
这次两个都删掉:
t1 = Temp() t2 = t1 del t1 del t2 print("-" * 10)
输出:
# 你被干掉了
# ----------
都删了,自然就真删掉了
这样搞比较麻烦,我们引入一下获取引用个数:getrefcount(object也会占1个引用计数)来个案例:
# 程序退出的时候,在他运行期间所有占用资源归还操作系统 # 引用计数 import sys t1 = Temp() print(sys.getrefcount(t1)) #(结果比实际引用大1)【object也会占1个引用计数】 t2 = t1 print(sys.getrefcount(t1)) print(sys.getrefcount(t2)) del t1 print(sys.getrefcount(t2)) # sys.getrefcount(t1)#被删掉自然没有了 del t2 print("-" * 10)
运行结果:
2
3
3
2
你被干掉了
----------
我再贴一种情况,你可以思考下为啥:
t1 = Temp() t2 = Temp() del t1 del t2 print("-" * 10)
输出:
# 你被干掉了
# 你被干掉了
# ----------
小潘扭过头瞅了一眼说道:“大叔,你__new__忘记写案例了”
小明一愣神,立马反应过来说:“我这叫谋而后动~”
当你实例化一个对象的时候,就会执行new 方法里面的方法。new方法在类定义中不是必须写的,如果没定义,默认会调用object.new去创建一个对象
__new__方法中至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供
__new__方法中必须要有返回值(返回实例化出来的实例)
小明翻阅了官方文档,淡定的打下了如下标准格式的代码:
class Dog(object): def __init__(self, name): self.name = name print("初始化完毕") def __str__(self): return "Dog的名字叫:%s" % self.name def __new__(cls, name): # 注意参数,是cls,然后其他参数和init保持一致即可 print("创建对象完毕") # 别忘记写返回值哦 return object.__new__(cls) def main(): happy = Dog("Happy") print(happy) if __name__ == '__main__': main()
创建对象完毕 初始化完毕 Dog的名字叫:Happy
关于__name__在模块调用的时候会详细说,你可以先这样理解:如果直接运行py文件就执行,别人调用那么你的main就不执行了
标准写法:
# 1.导入的模块 # 2.class的定义 # 3.其他方法定义 def main(): pass if __name__ == '__main__': main()
其他内容后面会继续说,封装部分再说说静态方法和类方法之类的就结束了(和C#还是有很大区别的)
1.7 类属性、实例属性
小明问老师:“老师老师,怎么没有静态类,静态属性之类的东西呢?”
老师笑而不语道:“小家伙原来不仅仅是体重增加啊,这求知欲也是大大的增加呢 ~ 且听我慢慢道来”
类在程序里面也是对象(你姑且可以认为所有的类都类似于C#里面的静态类),而通过类实例化的对象,叫实例化对象
实例属性 --> 实例对象相互之间不共享 一般我们都是在__init__
中定义
类属性(类似于C#里面的静态字段) --> 属于类对象,多个实例对象之间共享
注意一下:相同名称的实例属性将屏蔽掉类属性(尽量别同名)
类属性除了可以通过 类名.类属性 访问外,还可以直接 实例对象.类属性 (C#中抽象类和静态类是不能被实例化的)
来个案例更直观点:
class Person(object): # age为类属性 age = 1 def __init__(self, name): # name为实例属性 self.name = name def main(): # 类名.类属性 print(Person.age) xiaoming = Person("小明") # 对象.类属性 print(xiaoming.age) if __name__ == '__main__': main()
1 1
如果需要在类外 修改类属性,必须通过类对象去引用然后进行修改
如果通过实例对象去引用,会产生一个同名的实例属性,这种方式修改的是实例属性,不会影响到类属性
如果通过实例对象去引用该名称的属性,实例属性会强制 屏蔽掉类属性,即引用的是实例属性,除非del了该实例属性才能正常访问类属性
你可以理解为,Python这么做只是为了方便你获取,该怎么修改还得怎么做。来看个案例:
class Person(object): # age为类属性 age = 1 def __init__(self, name): # name为实例属性 self.name = name def main(): # 类名.类属性 print(Person.age) # 通过对象.类属性修改 xiaoming = Person("小明") xiaoming.age = 100 print(xiaoming.age) # 其实,并没有修改成功,只是产生了一个同名age print(Person.age) # 对吧,类属性并没有被修改 # 通过类名修改 Person.age = 22 # 如果需要在类外修改类属性,必须通过类对象去引用然后进行修改 print(xiaoming.age) # 刚才已经创建一个同名age,所以现在显示的是刚才的值 print(Person.age) # 通过类名.类属性 就可以看到值被修改了 # 如果你还是不信,可以创建一个新对象看看 xiaopan = Person("小潘") print(xiaopan.age) # xiaoming实例对象想访问怎么办? # 除非del了该实例属性才能正常访问类属性 del xiaoming.age print(xiaoming.age) # 这时候访问的就是 类属性 了 if __name__ == '__main__': main()
1 100 1 100 22 22 22
1.8 实例方法、类方法、静态方法
先说说 实例方法,实例方法第一个定义的参数只能是实例本身引用self
,只能通过实例调用(就是我们之前用的 def func_name(self,xxx):
)
类方法:是类对象所拥有的方法,需要用修饰器@classmethod
来标识,第一个参数必须是类对象cls
,可以通过类或者实例直用
静态方法:定义静态方法使用装饰器@staticmethod
,没有默认的必须参数,通过类和实例直接调用
静态方法中不需要额外定义参数,因此在静态方法中引用类属性的话,必须通过 类对象来引用(访问)
小明眼花缭乱的对老师说道,老师给我看几个案例吧:
class Dog(object): # 类属性 name = "小汪" # 实例方法 def __init__(self, age): # 实例属性 self.age = age # 打印看看 print("self id:%s" % id(self)) # 类方法 @classmethod def show_name(cls): # 访问类属性 cls.xxx print("我叫%s" % cls.name) # 打印看看 print("cls id:%s" % id(cls)) # 静态方法 @staticmethod def say_hello(): print("汪汪汪") def main(): # 类名方式访问 Dog.show_name() Dog.say_hello() # 类名的方式可以访问静态方法 # 实例对象方式访问 dog = Dog(2) dog.show_name() dog.say_hello() if __name__ == '__main__': main()
我叫小汪 cls id:94310818174200 汪汪汪 self id:140392216464016 我叫小汪 cls id:94310818174200 汪汪汪
一般都是这样用的(供参考):
实例方法:一般平时用的都是它
类方法:类方法用在模拟C#多个构造函数(Python里面不能有同名函数) or 你需要 对类属性、类方法操作之类的
静态方法:一般 都是独立功能,类似于函数,只不过在面向对象里面一般这么用
1.9 C#封装案例
C#面向对象比较优美,来个封装的案例基本上就搞定了:
using System; namespace _1Encapsulation { public class Student { /// <summary> /// 字段 /// </summary> private int _age; /// <summary> /// 属性 /// </summary> public int Age { get { return _age; } set { if (value > 1) { _age = value; } } } /// <summary> /// 自动化属性 /// </summary> public string Name { get; set; } /// <summary> /// 自动属性必须要有get访问器 /// </summary> public string SNum { get; } private int _gender; public int Gender { set { _gender = value; } } /// <summary> /// 构造函数的名字必须与类名一致 /// 构造函数没有返回值也没有viod /// 默认自动生成一个无参构造函数,当有一个有参构造函数的时候无参构造函数便不会自动创建 /// </summary> public Student() { } /// <summary> /// 有参构造函数 /// </summary> /// <param name="name"></param> /// <param name="age"></param> public Student(string name, int age) { this.Name = name; this.Age = age; } /// <summary> /// this调用当前类的某个有参构造函数 /// </summary> /// <param name="name"></param> /// <param name="age"></param> /// <param name="gender"></param> public Student(string name, int age, int gender) : this(name, age) { this.Gender = gender; } /// <summary> /// 某个方法 /// </summary> public void Show() { Console.WriteLine("Name:" + this.Name + " Age:" + this.Age + "\n"); } public override string ToString() { return "Name:" + this.Name + " Age:" + this.Age; } } }
调用部分:
using System; namespace _1Encapsulation { class Program { static void Main(string[] args) { Student s = new Student() { Name = "mmd", Age = 13, Gender = 1 }; s.Show(); Student s1 = new Student("dmm", 20); s1.Show(); Console.WriteLine(s); } } }
Python3 与 NetCore 基础语法对比(Function专栏)
文章汇总:https://www.cnblogs.com/dotnetcrazy/p/9160514.html
汇总系列:https://www.cnblogs.com/dunitian/p/4822808.html#ai
最新彩色版:https://www.cnblogs.com/dotnetcrazy/p/9175950.html
昨晚开始写大纲做demo,今天牺牲中午休息时间码文一篇,希望大家点点赞 O(∩_∩)O
NetCore:https://github.com/lotapp/BaseCode/tree/master/netcore/1_POP/6func
Python:https://github.com/lotapp/BaseCode/tree/master/python/1.POP/4.func_IO
在线演示:http://nbviewer.jupyter.org/github/lotapp/BaseCode/tree/master/python/notebook/1.POP/4.func
主要是普及一下Python基础语法,对比着Net,新手更容易上手。对比学习很有意思的,尤其是一些底层和思路
本来感觉函数要说的地方没多少,细细一规划,发现~还是单独拉出一篇说说吧,之后就进入面向对象了,函数还是有必要了解一下的,不然到时候Class里面的方法定义又要说了。
演示的模式一直在变,刚开始让大家熟悉一下VSCode,后来引入了ipython交互式编程的概念,现在就用前几天讲的Notebook来演示了(VSCode现在也有这个预览版的插件了)
直接跳到扩展系列:https://www.cnblogs.com/dotnetcrazy/p/9175950.html#ext
先从函数定义说起吧:
# 定义一个空函数:(不写pass就报错了)
# 定义一个无参函数(注意缩进)
# 定义一个含参函数
扩:文档说明用""" 或者'''来定义,就是如下效果
# 定义一个含默认参数(缺省参数)的函数
# 定义有返回值的函数
# 定义含有多个返回值的函数(利用了元组)
来个案例解释一下:(多返回值只是一种假象,Python函数返回的仍然是单一值~元组)
传多个参数系列:(上面那个多返回参数也可以返回一个list来实现类似效果)
引用传递(通过元组、列表实现):扩展有可变类型和不可变类型作为形参的对比
# 定义一个可变参数的函数(参数名字一般都是*args)
如果你需要传一个元组或者列表进去的话,可以参数前面加*# 定义含关键字参数的函数:def default_kv_params(name,age=23,**kv):# 可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple
# 关键字参数允许你传入0个或任意个含key-value的参数,自动组装为一个dict来个综合案例:def default_god_params(name,age=23,*args,**kv):
需要注意py里面的书写格式==》先定义再调用(Code参考)
NetCore:(C#基础语法大家都很熟了,我贴一个注释的Code即可)VSCode里面如果也想像VS一样,///就生成注释==》请安装函数文档注释:XML Documentation Comments
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141using
System;
using
System.Collections.Generic;
namespace
_6func
{
class
Program
{
static
void
Main(
string
[] args)
{
#region Base
// # 定义一个空函数:
Method();
// # 定义一个无参函数
GetName();
// # 定义一个含参函数
ShowInfos(
"李四"
, 22);
// # 定义一个含默认参数(缺省参数)的函数
DefaultParam(
"张三"
);
// # 定义有返回值的函数
int
result = DivHaveReturn(1, 2);
Console.WriteLine($
"计算结果为{result}"
);
#endregion
// # 定义含有多个返回值的函数(利用了元组)
var
(sum, dvalue) = DivHaveReturns(1, 2);
Console.WriteLine($
"sum:{sum},D-value:{dvalue}"
);
// 传多个参数系列:
// 引用传递(通过元组、列表实现):扩展有可变类型和不可变类型作为形参的对比
var
list =
new
List<
int
>() { 1, 2, 3, 4, 5 };
Console.WriteLine(DefaultSomeParams(list));
Console.WriteLine(list.Count);
//这就是引用传递的证明
// # 定义一个可变参数的函数(参数名字一般都是*args)
Console.WriteLine(DefaultParams(1, 2, 3, 4, 5));
// # 定义含关键字参数的函数 直接传Dict
}
#region base
/// <summary>
/// 定义一个空函数
/// </summary>
private
static
void
Method()
{
}
/// <summary>
/// 定义一个无参函数
/// </summary>
// private static void GetName()
// {
// Console.WriteLine("你好");
// }
//简写
private
static
void
GetName() => Console.WriteLine(
"你好"
);
/// <summary>
/// 定义一个含参数的函数
/// </summary>
/// <param name="name">名字</param>
/// <param name="age">年龄</param>
// private static void ShowInfos(string name, int age)
// {
// Console.WriteLine($"我叫{name} 我的年龄是{age}");
// }
//简写
private
static
void
ShowInfos(
string
name,
int
age) => Console.WriteLine($
"我叫{name} 我的年龄是{age}"
);
/// <summary>
/// 定义一个含缺省参数的函数
/// </summary>
/// <param name="name">名字</param>
/// <param name="age">年龄默认23</param>
// private static void DefaultParam(string name, int age = 23)
// {
// Console.WriteLine($"我叫{name} 我的年龄是{age}");
// }
//简写
private
static
void
DefaultParam(
string
name,
int
age = 23) => Console.WriteLine($
"我叫{name} 我的年龄是{age}"
);
/// <summary>
/// 定义一个有返回值的函数(计算a+b,返回计算结果)
/// </summary>
/// <param name="a">num1</param>
/// <param name="b">num2</param>
// private static int DivHaveReturn(int a, int b)
// {
// return a + b;
// }
//简写
private
static
int
DivHaveReturn(
int
a,
int
b) => a + b;
#endregion
/// <summary>
/// 定义含有多个返回值的函数(利用了元组)
/// 计算a+b的和,计算a-b,并返回两个结果
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns></returns>
// private static (int sum,int dValue) DivHaveReturns(int a, int b)
// {
// return ((a+b),(a-b));
// }
//简写
private
static
(
int
sum,
int
dValue) DivHaveReturns(
int
a,
int
b) => ((a + b), (a - b));
#region 传入多个参数系列
/// <summary>
/// 利用列表实现,引用传递之类的C#还有ref和out,这边就不说了
/// </summary>
/// <param name="nums"></param>
/// <returns></returns>
private
static
int
DefaultSomeParams(List<
int
> numList)
{
int
sum = 0;
foreach
(
var
item
in
numList)
{
sum += item;
}
numList.Clear();
return
sum;
}
/// <summary>
/// 定义一个可变参数的函数
/// </summary>
/// <param name="args"></param>
/// <returns></returns>
private
static
int
DefaultParams(
params
int
[] args)
{
int
sum = 0;
foreach
(
var
item
in
args)
{
sum += item;
}
return
sum;
}
#endregion
}
}
1.递归函数:函数递归调用其实就是自己调用自己,关键点只要考虑什么时候跳出即可(没有跳出就是死循环)先来个简单的案例熟悉一下:来个案例(实际工作中并不会自己定义,用系统自带strip方法即可)C#的递归我就引用一下以前的Code:https://github.com/dunitian/LoTCodeBase/blob/master/NetCode/1.面向过程/01.基础/10.递归案例/Program.cs
2.匿名函数系列:lambda 参数: 表达式来个经常用的案例:data_list.sort(key=lambda x:x["key"])还有一个比较常用的地方:(当参数传递)NetCore:上面Code中的简写都是用匿名函数的方式,可以参考
3.全局变量和局部变量有人可能会说,这个就太简单了,没啥好说的,(⊙o⊙)… Python还真需要说说,来个案例给你猜结果:直接看结果吧:发现全局变量a木有被修改,而b修改了还是来个简单案例说明下吧~# 这是因为,python定义一个变量的写法不用加类型导致的(⊙﹏⊙) 所以函数里面a=200,python解释器就认为你定义了一个和a这个全局变量名字相同的局部变量,那怎么用呢?global来声明一下全局变量即可:
总结:# 在函数中不使用global声明全局变量不能修改全局变量==>本质是不能修改全局变量的指向,即不能将全局变量指向新的数据# 对于不可变类型的全局变量来说,因其指向的数据不能修改,所以不使用global时无法修改全局变量# 对于可变类型的全局变量来说,因其指向的数据可以修改,所以不使用global时也可修改全局变量
下面就进入验证扩展系列,看看一些概念:# 之前很多资料说py3匿名函数里不能调用print函数,自己测试下
# 可变类型与不可变类型的变量分别作为函数参数的区别# 感到疑惑可以看之前的运算符扩展(https://www.cnblogs.com/dotnetcrazy/p/9155310.html#ext)# Python中函数参数都是引用传递
# 对于不可变类型,因变量不能修改,所以运算不会影响到变量自身
# 而对于可变类型来说,函数体中的运算有可能会更改传入的参数变量
# 函数名能不能重复的问题(能不能重载:具有不同的参数的类型或参数的个数【跟返回值没关系】)结论:函数名不能重名
来两个有趣的扩展:1.交换两个数熟悉吧,编程第一课,除了用第三变量 或者 两数相加减 实现外,Python还有一种新方式:a,b=b,aNetCore:这个我也是刚知道,O(∩_∩)O哈哈~还得谢谢评论区的兄弟^_^
2.eval(和js里面的eval差不多):不太建议使用
[C#]C#时间日期操作
一、C# 日期格式
1. DateTime dt = DateTime.Now;
2. dt.ToString();//2005-11-5 13:21:25
3. dt.ToFileTime().ToString();//127756416859912816
4. dt.ToFileTimeUtc().ToString();//127756704859912816
5. dt.ToLocalTime().ToString();//2005-11-5 21:21:25
6. dt.ToLongDateString().ToString();//2005年11月5日
7. dt.ToLongTimeString().ToString();//13:21:25
8. dt.ToOADate().ToString();//38661.5565508218
9. dt.ToShortDateString().ToString();//2005-11-5
10. dt.ToShortTimeString().ToString();//13:21
11. dt.ToUniversalTime().ToString();//2005-11-5 5:21:25
12. dt.Year.ToString();//2005
13. dt.Date.ToString();//2005-11-5 0:00:00
14. dt.DayOfWeek.ToString();//Saturday
15. dt.DayOfYear.ToString();//309
16. dt.Hour.ToString();//13
17. dt.Millisecond.ToString();//441
18. dt.Minute.ToString();//30
19. dt.Month.ToString();//11
20. 22. dt.Second.ToString();//28
21. 23. dt.Ticks.ToString();//632667942284412864
22. 24. dt.TimeOfDay.ToString();//13:30:28.4412864
23. 25. dt.ToString();//2005-11-5 13:47:04
24. dt.AddYears(1).ToString();//2006-11-5 13:47:04
25. dt.AddDays(1.1).ToString();//2005-11-6 16:11:04
26. dt.AddHours(1.1).ToString();//2005-11-5 14:53:04
27. dt.AddMilliseconds(1.1).ToString();//2005-11-5 13:47:04
28. dt.AddMonths(1).ToString();//2005-12-5 13:47:04
29. dt.AddSeconds(1.1).ToString();//2005-11-5 13:47:05
30. dt.AddMinutes(1.1).ToString();//2005-11-5 13:48:10
31. dt.AddTicks(1000).ToString();//2005-11-5 13:47:04
32. dt.Add(?).ToString();//问号为一个时间段
33. dt.Equals("2005-11-6 16:11:04").ToString();//False
34. dt.Equals(dt).ToString();//True
35. dt.GetHashCode().ToString();//1474088234
36. dt.GetType().ToString();//System.DateTime
37. dt.GetTypeCode().ToString();//DateTime
38.
39. dt.GetDateTimeFormats('s')[0].ToString();//2005-11-05T14:06:25
40. dt.GetDateTimeFormats('t')[0].ToString();//14:06
41. dt.GetDateTimeFormats('y')[0].ToString();//2005年11月
42. dt.GetDateTimeFormats('D')[0].ToString();//2005年11月5日
43. dt.GetDateTimeFormats('D')[1].ToString();//2005 11 05
44. dt.GetDateTimeFormats('D')[2].ToString();//星期六 2005 11 05
45. dt.GetDateTimeFormats('D')[3].ToString();//星期六2005年11月5日
46. dt.GetDateTimeFormats('M')[0].ToString();//11月5日
47. dt.GetDateTimeFormats('f')[0].ToString();//2005年11月5日14:06
48. dt.GetDateTimeFormats('g')[0].ToString();//2005-11-5 14:06
49. dt.GetDateTimeFormats('r')[0].ToString();//Sat, 05 Nov 2005 14:06:25 GMT
50.
51. string.Format("{0:d}",dt);//2005-11-5
52. string.Format("{0:D}",dt);//2005年11月5日
53. string.Format("{0:f}",dt);//2005年11月5日14:23
54. string.Format("{0:F}",dt);//2005年11月5日14:23:23
55. string.Format("{0:g}",dt);//2005-11-5 14:23
56. string.Format("{0:G}",dt);//2005-11-5 14:23:23
57. string.Format("{0:M}",dt);//11月5日
58. string.Format("{0:R}",dt);//Sat, 05 Nov 2005 14:23:23 GMT
59. string.Format("{0:s}",dt);//2005-11-05T14:23:23
60. string.Format("{0:t}",dt);//14:23
61. string.Format("{0:T}",dt);//14:23:23
62. string.Format("{0:u}",dt);//2005-11-05 14:23:23Z
63. string.Format("{0:U}",dt);//2005年11月5日6:23:23
64. string.Format("{0:Y}",dt);//2005年11月
65. string.Format("{0}",dt);//2005-11-5 14:23:23
66. string.Format("{0:yyyyMMddHHmmssffff}",dt);
二、日期格式模式 说明
d 月中的某一天。一位数的日期没有前导零。
dd 月中的某一天。一位数的日期有一个前导零。
ddd 周中某天的缩写名称,在 AbbreviatedDayNames 中定义。
dddd 周中某天的完整名称,在 DayNames 中定义。
M 月份数字。一位数的月份没有前导零。
MM 月份数字。一位数的月份有一个前导零。
MMM 月份的缩写名称,在 AbbreviatedMonthNames 中定义。
MMMM 月份的完整名称,在 MonthNames 中定义。
y 不包含纪元的年份。如果不包含纪元的年份小于 10,则显示不具有前导零的年份。
yy 不包含纪元的年份。如果不包含纪元的年份小于 10,则显示具有前导零的年份。
yyyy 包括纪元的四位数的年份。
gg 时期或纪元。如果要设置格式的日期不具有关联的时期或纪元字符串,则忽略该模式。
h 12 小时制的小时。一位数的小时数没有前导零。
hh 12 小时制的小时。一位数的小时数有前导零。
H 24 小时制的小时。一位数的小时数没有前导零。
HH 24 小时制的小时。一位数的小时数有前导零。
m 分钟。一位数的分钟数没有前导零。
mm 分钟。一位数的分钟数有一个前导零。
s 秒。一位数的秒数没有前导零。
ss 秒。一位数的秒数有一个前导零。
f 秒的小数精度为一位。其余数字被截断。
ff 秒的小数精度为两位。其余数字被截断。
fff 秒的小数精度为三位。其余数字被截断。
ffff 秒的小数精度为四位。其余数字被截断。
fffff 秒的小数精度为五位。其余数字被截断。
ffffff 秒的小数精度为六位。其余数字被截断。
fffffff 秒的小数精度为七位。其余数字被截断。
t 在 AMDesignator 或 PMDesignator 中定义的 AM/PM 指示项的第一个字符(如果存在)。
tt 在 AMDesignator 或 PMDesignator 中定义的 AM/PM 指示项(如果存在)。
z 时区偏移量(“+”或“-”后面仅跟小时)。一位数的小时数没有前导零。例如,太平洋标准时间是“-8”。
zz 时区偏移量(“+”或“-”后面仅跟小时)。一位数的小时数有前导零。例如,太平洋标准时间是“-08”。
zzz 完整时区偏移量(“+”或“-”后面跟有小时和分钟)。一位数的小时数和分钟数有前导零。例如,太平洋标准时间是“-08:00”。
: 在 TimeSeparator 中定义的默认时间分隔符。
/ 在 DateSeparator 中定义的默认日期分隔符。
% c 其中 c 是格式模式(如果单独使用)。如果格式模式与原义字符或其他格式模式合并,则可以省略“%”字符。
\ c 其中 c 是任意字符。照原义显示字符。若要显示反斜杠字符,请使用“\\”。
只有上面第二个表中列出的格式模式才能用于创建自定义模式;在第一个表中列出的标准格式字符不能用于创建自定义模式。
自定义模式的长度至少为两个字符;例如,
1. DateTime.ToString( "d"); // 返回 DateTime 值;“d”是标准短日期模式。
2. DateTime.ToString( "%d"); // 返回月中的某天;“%d”是自定义模式。
3. DateTime.ToString( "d "); // 返回后面跟有一个空白字符的月中的某天;“d”是自定义模式。
三、C# 常用日期处理函数
// 计算2个日期之间的天数差
1. DateTime dt1 = Convert.DateTime("2007-8-1");
2. DateTime dt2 = Convert.DateTime("2007-8-15");
3. TimeSpan span = dt2.Subtract(dt1);
4. int dayDiff = span.Days + 1;
// 计算某年某月的天数
1. int days = DateTime.DaysInMonth(2007, 8);
2. days = 31;
// 给日期增加一天、减少一天
1. DateTime dt =DateTime.Now;
2. dt.AddDays(1); //增加一天
3. dt.AddDays(-1);//减少一天
*注:以下的毫秒都采用最大997,而不是999 因为SQL SERVER的精度为3毫秒
//本月的天数
int daysInMonth = DateTime.DaysInMonth(DateTime.Now.Year, DateTime.Now.Month);
//本年的天数 是否是闰年
int daysInYear = DateTime.IsLeapYear(DateTime.Now.Year) ? 366 : 365;
//本月第一天
DateTime firstDayInMonth = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1);
//本月的最后一天 本月1号加一个月得下月1号,再剪掉一天就是本月最后一天
DateTime lastDayInMonth = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1).AddMonths(1).AddDays(-1);
//本月最后一天的午夜
DateTime lastDayInMonth2 = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1).AddMonths(1).AddMilliseconds(-3);
//本年第一天
DateTime firstDayInYear = new DateTime(DateTime.Now.Year, 1, 1);
//本年最后一天
DateTime lastDayInYear = new DateTime(DateTime.Now.Year, 12, 31);
//本年最后一天的午夜
DateTime lastDayInYear2 = new DateTime(DateTime.Now.Year, 12, 31, 23, 59, 59, 997);
//得到星期几 星期天为7
int dayOfWeek = Convert.ToInt32(DateTime.Now.DayOfWeek) < 1 ? 7 : Convert.ToInt32(DateTime.Now.DayOfWeek);
//本周一
DateTime monday = new DateTime(DateTime.Now.Year,DateTime.Now.Month,DateTime.Now.Day).AddDays(1 - dayOfWeek);
//本周 星期天
DateTime sunday = monday.AddDays(6);
//本周 星期天的午夜
DateTime sunday2 = monday.AddDays(7).AddMilliseconds(-3);
//本季度第一天
DateTime firsyDayInQuarter = new DateTime(DateTime.Now.Year, DateTime.Now.Month - (DateTime.Now.Month - 1) % 3, 1);
//本季度最后一天
DateTime lastDayInQuarter = firsyDayInQuarter.AddMonths(3).AddDays(-1);
//本季度最后一天的午夜
DateTime lastDayInQuarter2 = firsyDayInQuarter.AddMonths(3).AddMilliseconds(-3);
string datetime = "10-Jul-09";
string newdatetime = DateTime.Parse(datetime, new System.Globalization.CultureInfo("de-de")).ToString("yyyyMMdd");
四、C#比较两时间大小
1、比较时间大小的实验
string st1="12:13";
string st2="14:14";
DateTime dt1=Convert.ToDateTime(st1);
DateTime dt2=Convert.ToDateTime(st2);
DateTime dt3=DateTime.Now;
if(DateTime.Compare(dt1,dt2)>0)
msg.Text=st1+">"+st2;
else
msg.Text=st1+"<"+st2;
msg.Text+="\r\n"+dt1.ToString();
if(DateTime.Compare(dt1,dt3)>0)
msg.Text+="\r\n"+st1+">"+dt3.ToString();
else
msg.Text+="\r\n"+st1+"<"+dt3.ToString();
2、计算两个时间差值的函数,返回时间差的绝对值:
private string DateDiff(DateTime DateTime1,DateTime DateTime2)
{
string dateDiff=null;
try
{
TimeSpan ts1=new TimeSpan(DateTime1.Ticks);
TimeSpan ts2=new TimeSpan(DateTime2.Ticks);
TimeSpan ts=ts1.Subtract(ts2).Duration();
dateDiff=ts.Days.ToString()+"天" +ts.Hours.ToString()+"小时"+ts.Minutes.ToString()+"分钟" +ts.Seconds.ToString()+"秒";
}
catch
{
}
return dateDiff;
}
3、实现计算DateTime1-36天=DateTime2的功能
TimeSpan ts=new TimeSpan(40,0,0,0);
DateTime dt2=DateTime.Now.Subtract(ts);
msg.Text=DateTime.Now.ToString()+"-"+ts.Days.ToString()+"天\r\n"; msg.Text+=dt2.ToString();
[C#]C#中字符串的操作
1.Replace(替换字符):
public string Replace(char oldChar,char newChar);在对象中寻找oldChar,如果寻找到,就用newChar将oldChar替换掉。
如:
string st = "abcdef";
string newstring = st.Replace('a', 'x');
Console.WriteLine(newstring); //即:xbcdef
public string Replace(string oldString,string newString);在对象中寻找oldString,如果寻找到,就用newString将oldString替换掉。
如:
string st = "abcdef";
string newstring = st.Replace("abc", "xyz");
Console.WriteLine(newstring); //即:xyzdef
2.Remove(删除字符):
public string Remove(int startIndex);从startIndex位置开始,删除此位置后所有的字符(包括当前位置所指定的字符)。
如:
string st = "abcdef";
string newstring = st.Remove(4);
Console.WriteLine(newstring); //即:abcd
public string Remove(int startIndex,int count);从startIndex位置开始,删除count个字符。
如:
string st = "abcdef";
string newstring = st.Remove(4,1);
Console.WriteLine(newstring); //即:abcdf
3.Substring(字符串提取):
public string Substring(int startIndex);从startIndex位置开始,提取此位置后所有的字符(包括当前位置所指定的字符)。
如:
string st = "abcdef";
string newstring = st.Substring(2);
Console.WriteLine(newstring); //即:cdef
public string Substring(int startIndex,int count);从startIndex位置开始,提取count个字符。
如:
string st = "abcdef";
string newstring = st.Substring(2,2);
Console.WriteLine(newstring); //即:cd
4.Trim(清空空格):
public string Trim ():将字符串对象包含的字符串两边的空格去掉后返回。
public string Trim ( params char[] trimChars ):从此实例的开始和末尾移除数组中指定的一组字符的所有匹配项。
如:
string st ="abcdef";
string newstring = st.Trim(new char[] {'a'});//寻找st字符串中开始与末尾是否有与'a'匹配,如有,将其移除。
Console.WriteLine(newstring); //即:bcdef
注:如果字符串为"aaaabcdef",返回依然为bcdef。当移除第一个a时,开始依然为a,继续移除,直到没有。
public string TrimEnd ( params char[] trimChars ):对此实例末尾与指定字符进行匹配,true则移除
public string TrimStart ( params char[] trimChars ):对此实例开始与指定字符进行匹配,true则移除
5.ToLower(转换大小写)
public string ToLower():将字符串对象包含的字符串中的大写全部转换为小写。
6.IndexOf(获取指定的字符串的开始索引)
public int IndexOf (sring field):在此实例中寻找field,如果寻找到,返回开始索引,反之,返回-1。
如:
string st = "abcdef";
int num=st.IndexOf("bcd");
Console.WriteLine(num); //即:1
7.Equals(是否相等)
public bool Equals (string value):比较调用方法的字符串对象包含字符串和参数给出的对象是否相同,如相同,就返回true,反之,返回false。
如: string a = "abcdef";
bool b = a.Equals("bcdef");
Console.WriteLine(b);//即:false
public bool Equals ( string value, StringComparison comparisonType ):比较调用方法的字符串对象包含字符串和参数给出的对象是否在不区分大小写的情况下相同,如相同,就返回true,反之,返回false,第二个参数将指定区域性、大小写以及比较所用的排序规则.
如:
string a = "ABCDEF";
bool b = a.Equals("abcdef",StringComparison.CurrentCultureIgnoreCase);
Console.WriteLine(b);//即:true
8.Split(拆分)
public string[] Split ( params char[] separator ):根据separator 指定的没有字符分隔此实例中子字符串成为Unicode字符数组, separator可以是不包含分隔符的空数组或空引用。
public string[] Split ( char[] separator, int count ):参数count 指定要返回的子字符串的最大数量。
如:
string st = "语文|数学|英语|物理";
string[] split = st.Split(new char[]{'|'},2);
for (int i = 0; i < split.Length; i++)
{
Console.WriteLine(split[i]);
}
注:count不填则全部拆分
public enum StringSplitOptions
成员名称 说明
None 返回值包括含有空字符串的数组元素
RemoveEmptyEntries 返回值不包括含有空字符串的数组元素
如:
string st = "语文|数学||英语|物理";
string[] split = st.Split(new char[]{'|'},StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < split.Length; i++)
{
Console.WriteLine(split[i]);
}
将StringSplitOptions枚举和Split()方法联系起来:
1. public string[] Split ( char[] separator, StringSplitOptions options ):options指定StringSplitOptions枚举的RemoveEmptyEntries以省略返回的数组中的空数组元素,或指定StringSplitOptions枚举的None以包含返回的数组中的空数组元
2. public string[] Split ( char[] separator, int count, StringSplitOptions options )
3. public string[] Split ( string[] separator, StringSplitOptions options )
4. public string[] Split ( string[] separator, int count, StringSplitOptions options )
9.Contains(判断是否存在)
public bool Contains(string text):如果字符串中出现text,则返回true,反之false,如果text为("")也返回true。
如:
string st="语文数学英语";
bool b=st.Contains("语文");
Console.WriteLine(b);//true
10.EndsWith,StartsWith(判断字符串的开始或结束)
public bool EndsWith ( string value ):判断对象包含字符串是否以value指定的字符串结束,是则为 true;否则为 false。
public bool EndsWith ( string value, StringComparison comparisonType ):第二个参数设置比较时区域、大小写和排序规则。
public bool StartsWith ( string value ):判断对象包含字符串是否以value指定的字符串开始,是则为 true;否则为 false。
public bool StartsWith ( string value, StringComparison comparisonType ) :第二个参数设置比较时区域、大小写和排序规则。
如:
string st="语文数学英语abc";
bool b=st.EndsWith("英语ABC",StringComparison.CurrentCultureIgnoreCase);//第二个参数忽略大小比较。
Console.WriteLine(b);//true
11.Insert(字符串插入)
public string Insert ( int startIndex, string value ):在指定的字符串下标为startIndex前插入字符串value。返回插入后的值。
如:
string st="语文数学英语abc";
string newst=st.Insert(6,"物理");//注:在指定索引“前”插入。
Console.WriteLine(newst);//即:语文数学英语物理abc
[ASP.NET]NTKO插件使用常见问题
一、环境要求
NTKO OFFICE文档控件能够在IE、谷歌Chrome、Firefox等浏览器中直接编辑MS Office、WPS、金山电子表、永中Office等文档并保存到WEB服务器。(标准版对IE浏览器的兼容进行了验证,其他浏览器并未验证)
使用Ntkooffice套打,对配置环境要求较高,以MS office为例,需要安装完整版Office。
备注:文档控件是ActiveX控件,通过浏览器操作本地的office,所以说系统用户的权限必须管理员身份,这样控件才能正常的加载;还有就是访问的系统里面有文档控件,必须将这个系统加入到IE的可信任站点中去;
加入可信站点如图:IE工具栏-Internet选项
这保护模式不要启用;
这https验证取消,然后点击添加就行了;
如果在使用文档控件,在office文档和表单中的附件一并保存的时候出现失败;
检查一下IE安全设置,将“将文件上载到服务器时包含了本地目录路径” 启用 如图:
二、常见错误
2.1 问题:弹出下图“对象不支持”提示
解决方法:第一次运行时需要允许加载项,然后刷新后重新打开打印页面。
2.2 问题:NTKO OFFICE文档控件不能自动装载
原因分析:控件不能自动加载主要有以下原因导致
1)本地Internet选项中的安全设定,在当前区域禁止下载已签名的ActiveX控件;
2)引用控件的网页中,<object 标记中的codebase属性指定不正确,导致浏览器无法下载OfficeControl.cab文件;
3)服务器上的OfficeControl.cab被破坏,失去正确的签名,或者使用了不正确的版本;
4)虽然服务器上的OfficeControl.cab正确,但是浏览器下载的有问题。这个可能会因为某些WEB服务器的mime的错误配置引起,导致服务器将OfficeControl.cab不以二进制文件的形式发送给浏览器;
5)本地Internet选项中的安全设定,在当前区域不允许运行ActiveX控件和插件;
6)还有可能是由于微软的补丁引起,或者其他防病毒软件或者过滤软件阻止了控件安装;
解决方法:
1) 确认本地Internet选项中的安全设定中,允许下载已签名的ActiveX控件,并允许运行ActiveX控件和插件。
2)确认引用控件的网页中,<object 标记中的codebase=部分,正确指向了服务器上的OfficeControl.cab文件的URL[相对当前网页或者相对服务器根]。
3)从浏览器地址栏直接输入服务器上的OfficeControl.cab文件的URL,包含主机名,确认浏览器出现下载提示并且在下载保存后的OfficeControl.cab文件上,点击右键看属性,在出现的对话框中具有“数字签名”,且签名正确。
4)如果以上方法还不能解决问题,并且您的系统安装了“微软累积安全更新 MS05-052补丁”,请尝试如下步骤:
警告:如果使用注册表编辑器或其他方法错误地修改了注册表,则可能导致严重问题。这些问题可能需要重新安装操作系统才能解决。
1、单击“开始”,单击“运行”,键入 Regedit.exe,然后单击“确定”。
2、找到以下注册表子项:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\ActiveX Compatibility
3、右键单击“ActiveX Compatibility”,查找NTKO OFFICE文档控件的CLSID:{C9BC4DFF-4248-4a3c-8A49-63A7D317F404},如果该项目存在,右键单击右边的“Compatibility Flags”项目,然后单击“修改”。在“数值数据”框中,选择16进制,输入00800000,然后单击“确定”。
4、如果该NTKO OFFICE文档控件的CLSID不存在,则右键单击“ActiveX Compatibility”,指向“新建”,单击“项”,键入NTKO OFFICE文档控件的CLSID:{C9BC4DFF-4248-4a3c-8A49-63A7D317F404},然后按 Enter。
5、右键单击您在步骤 4 中创建的项,指向“新建”,然后单击“DWORD 值”。
6、键入 Compatibility Flags,然后按 Enter。
7、右键单击“Compatibility Flags”,然后单击“修改”。
8、在“数值数据”框中,选择16进制,输入00800000,然后单击“确定”。
9、退出注册表编辑器。
5)如果以上方法还不能解决问题,尝试暂时关闭防病毒软件或者其他过滤软件再进行安装。
6)如果还是不能解决问题,可能是机器配置被破坏,可以尝试进行手工安装。具体请参考相关文档。
2.3 问题:加载文档时出现“下载文档数据失败”对话框
解决方法:
错误原因是后台url数据错误。可以尝试从浏览器打开url,如果是后台错误,可以看到详细的错误信息。如果浏览器可以打开,控件不能打开,则可以试试设定控件属性<param name=”IsUseUTF8URL” value=”-1”>
2.4 问题:加载文档时出现“您没有正确安装OFFICE,或者请求创建一个系统不支持的OLE文档类型”错误
解决方法:
这个错误是因为接口没有注册。跟控件本身无关。可以尝试1、打开windows的“写字板”应用程序,选择插入word文档对象。如果这个出错,可以确定是office安装问题,或者是因为ole32.dll没有注册。2、可以尝试在命令行运行“regsvr32.dll”,再试试。3、如果不行,可以彻底卸载office,重新安装。
2.5 问题:控件为什么有时加载文档显示空白,有时可正常加载
这个可能是在body中直接调用OpenFromUrl/BeginOpenFromUrl,但此时控件并未完全初始化/加载完毕,所以出现空白。解决:可以在<body onload=”…”>中调用js函数,这样可以确保在浏览器加载控件完毕之后,才在该js函数中调用OpenFromUrl/BeginOpenFromUrl,这样就可以解决了
2.6 问题:文件存取错误
解决方法:
首先按照备注操作,将系统加入到IE的可信站点中去;如果加入了可信站点还是报文件存取错误的话那就是本机office的问题了,本机office是精简版的office,卸载了本机的然后重装一个完整的office;
1.环境问题,按照以下步骤检查
1)在写字板插入word对象试试,如果不报错,说明office是正确安装的
2)打开命令行,然后输入regsvr32 ole32.dll (win7需要这样打开:所有程序 附件 命令行#鼠标右键以管理员身份执行)
3)如果1)2)都没有问题,可以打开任务管理器看看是否有未结束的WINWORD.EXE EXCEL.EXE进程,关闭试试
4)删除normal.dot normal.dotx试试,这两个文件是office的模板文件,在目录C:\Documents and Settings\当前用户\Application Data\Microsoft\Templates下
5)windows7还可以尝试把OA或系统的IP加入信任站点,取消保护模式试试
6)如果以上方法都不行,请重新安装office试试(推荐完全安装)
只有部分文档打开时报错
2.文档被损坏
1)由于未知原因,文档被损坏,这时,可以把从本地打开这个文档,另存一份出来试试控件是否能打开
2.7 问题:使用文档控件打开服务器上面的文档时,出现文件传输错误
解决方法:
控件对象.openFromUrl(url);参数url必须能够返回标准文档的二进制数据流。它可以直接指向服务器上的一个word文档或者页面(这个页面读取文档的数据流,并返回给客户端)。
出现错误分为下面几种情况:
1:url错误。如果url没有问题在浏览器的地址栏直接输入url对应的全url应该能够下载word文档。如果url有问题,控件无法获取文档数据,就会提示“文件传输错误”。
2:编码问题。比如url中带有中文字符,浏览器对url编码导至url被破坏。服务器根据被破坏的url当然也不能返回正确的word二进制流。可以通过设置控件的isuseutf8url=-1(即使用utf8对url编码)。有的时候即使设置了isuseutf8url=-1也不能解决问题。根据经验,可以调用url=escape(url);来重新对url编码一次,然后再调用openFromUrl(url)。
3:服务器设置本身就不支持中文的url。比如tomcat服务器,是可以通过服务器配置文件来设置url编码,有的编码格式本来就不支持中文。这种情况就需要重新设置能够支持中文的url编码格式。
保存文档回服务器时报“文件传输错误” |
2.8 问题:控件使用一段时间后突然提示"您正在运行的NTKO OFFICE文档控件是演示版本已经到期,不能继续使用。(.net版本)
解决方法:
到标准版部署包中拷贝下图的3个文件 ,覆盖项目组对应路径下的文件。
2.9 问题:检测其他地方没有任何问题就是文档保存的时候出现不知名错误
解决方法:
可能引起的原因就是在:打开文档Openfromurl第二个参数或者BeginOpenfromURL第三个只读属性设置为true,这样就不能将文档保存回服务器;所以解决方案就是将这个参数设置为false就可以解决;
2.10 问题:当客户端的office版本含有2003、2007和2010,保存文档的时候怎样处理兼容问题
解决方法:
因为低版本的office不能兼容高版本的office文档格式(如office2003不能打开07和10文档),所以建议在保存文档时候可以使用SaveAsOtherFormatToURL方法,该方法用来将文档保存为其他格式的文件到指定的URL。除第一个参数之外,其他参数的格式以及返回值,和SaveToURL方法的参数一致。
第一个参数指明要保存的文件类型:
对Word文档而言,第一个参数的含义如下:
0:保存为word Txt格式;
1:保存为MHT格式。需要客户机安装OFFICE XP及以上版本;
2:保存为XML格式。需要客户机安装OFFICE 2003及以上版本;
3:保存为RTF格式;
4:保存为UnicodeText格式;
5:保存为兼容WORD文档格式;
对Excel文档而言,第一个参数的含义如下:
0:保存为Txt格式;
1:保存为MHT格式。需要客户机安装OFFICE XP及以上版本;
2:保存为XML格式。需要客户机安装OFFICE 2003及以上版本;
3:保存为CSV格式;
4:保存为UnicodeText格式;
5:保存为Excel7格式;
7:保存为Excel95格式;
对PowerPoint文档而言,第一个参数的含义如下:
0:保存为GIF格式;
1:保存为MHT格式。需要客户机安装OFFICE XP及以上版本;
2:保存为JPG格式。
3:保存为RTF格式;
4:保存为PNG格式;
三、其他
3.1 问题:页面分辨率问题
大屏显示器可能会存在页面显示不美观的问题
解决方法:需要使用大屏显示的项目组可以个性化调整页面。
3.2 问题:附件误删问题
假如已经打开证照并且编辑进行了保存操作,则会在框架目录下的对应文件夹下生成一个附件实例,这个时候如果误删实例,则会出现图2的错误。
EpointFrame\BigFileUpLoadStorage\2017\1\EpointFrame
图1:
图2:
3.3 问题:浏览器兼容性问题
标准版对IE及360浏览器做了兼容性验证:
兼容IE 不兼容360
对官网宣传的谷歌Chrome、Firefox浏览器未进行验证。
我对C#的认知。
关于开发者的技术水平到底该如何定义,到底一个人的技术水平应该定位在高、中、低的标准是什么呢?很多人觉得这是一个仁者见仁的问题,有人觉得根据公司的那个员工等级判断。答案是肯定不是,从纯开发技术的角度来分析。很多人觉得自己一门语言精通了就去学其他语言了,美其名曰集大成者,这样的工作十几年却是初级水平的技术人员也不少。
下面我来讲讲我的认知,C#这门技术到底学到什么程度可以进入到什么级别。
我常说C#的入门技术是委托、事件、消息。只有当你可以纯熟运用这三个技能的时候,才刚刚入门,此时C#的大门才算正式为你打开。很多人在学了一些语法编写一些项目后就觉得C#精通了,其实你们还没入门呢(对日开发的居多)
下面上一个图片,大家来看看自己的定位,当然是纯技术角度,其实,有些时候一个软件架构,用初级软件工程师也是可以架构的。
1, comom language runtime :初级人员无视他,中级人员起码要知道他,高级人员多数要会使用其中一些应用比如security,架构师要理解原理。
2, .netframework :这里有许多框架,会的越多越好。
3, Base class library :这里都是基本语法你会了多少呢,想成为高手一定要全部学会,一个都不能丢。
4, Runtime infrastructure library:这里内容初级开发者不用了解,进入中级就要开始一点点吸收了,想到高级要全部消化,是全部哦。
5, Framework calss library:这里都是基本应用,初级程序员肯能都会接触一些,中级就会了解和运用一些,高级就要全部会用。
6, Core concepts:这里的内容同上。
7, Core features,core objects,CLI language,DLR略过。。。
8, Desktop:CUI了解就行,GUI要深入了解,另外这里的涉及到了XAML语言,这个要学会。
9, Web:这里涉及的框架sharpoint如果工作没涉及不去了解也是可以的,但asp.net是必会的,其中的MVC就算工作没应用也要学会。Asp.net runtime是进阶高手的一个路障,了解的越多越好。Silverlight的话,会xaml基本就能用,如果工作需要精通。
10, SOA:这也是个必会的东西,而且至少要精一个。
11, Open web interface for .net:要了解,会使用,如果工作需要,要精通。
12, SDK:要了解,会基本使用。
13, Development:这个基本没有人能全会,但工具这个要熟练使用,毕竟工具会的越多越好,但不是技术加分。
14, Platforms:这个基本很难有人全精,但多少要了解,工作用过的要精通。
15, Productivity:起码nuget要会用。
16, Build:高级人员要了解原理。
17, Testing:至少要会使用1个,其他的要了解。
18, Deploy/publish:这个基本都百度的出用法,了解就可以,起码知道有这个东西,需要的时候可以百度。
19, Framework tool:这里有些是必会的,有些会用就行,但最好全部了解,需要的时候学习用法。
20, Data:这里内容作为高级人员是必会的,如果其中的orm可以用EF作为跳板深入研究(这里的水很深)。
21, Conponents:中级以后难免要接触这些,了解的越多进步的越多。
22, Concept:这是图片里没有的,中级以后就会接触的,像什么IOC,AOP,MVC,MVVM,DDD等等,在学习这些的过程中可以逐渐向架构师前进,其实这些概念学会了之后会发现,概念只是装逼用的。在概念里分为基本概念和高级概念,像IOC,AOP就是基本概念,这些东西在编码时你已经应用过了,而且有一些现成的开源代码,而且原理很简单,学会后可以用具体语言来把你编码的方式表达出来,不去了解也无妨,但知道的多了,方便忽悠;而DDD就是高级概念,光百度是学不会的,一定要应用过才能了解,但DDD这样的高级概念很复杂,非技术人员很难理解,技术人员也未必有那么好的口才讲解,而IOC,AOP这类的简单概念很容易理解,基本上口才笨拙的开发人员也能讲的很溜,很适合给领导很讲解。所以在领导看来,会基础概念和会高级概念都是一样一样一样地。
看到这里是不是那些以为C#很简单的同学就很吃惊啦啊,那些自以为自己是大神的是不是发现,原来自己不过才是刚入门的小菜鸟啦,那些以为自己C#精通的外包达人们,是不是打开图片后一脸陌生的感觉呀。其实,C#并不比其他语言简单,水深的狠,哪那么容易精通。
这些还只是C#,作为一个程序员,还要有其他必备的知识,比如HTML和CSS你得会,JS你得会,别说你知道标签是什么意思就说自己会了,起码DIV+CSS切图玩的起来才算会。数据库你得会,数据库水很深,别轻易说自己有初级DBA的水平,那些传说中每天备份表数据的初级DBA可是连入门都没有呢,不要和他们比;作为高级开发人员,起码存储过程要信手拈来把,起码要有解决过大数据死锁的经验吧。如果业余爱好再丰富一点的人,PS基本使用也要会把,falsh也要了解吧,3Dmax是不是也可以玩玩啊,程序员也要有美感嘛。此外,程序员要会写文档,解决方案可是基本技能,高级点的概要设计也是文档嘛。另外高级程序员难免还得写点ppt吧。
除了这些,还有一些要了解的东西,比如操作系统呀,硬件呀,软件工具等等,因为不一定什么时候你面对着一些性能bug,就需要他们的知识才能解决,或者解释。
再更上一层楼,要接触一些开源代码啦,现在Xamarin都开源了,你有去了解吗?很多开源代码都很厉害的,不要对我说在CSDN下载了一些开源代码啊。。。
【PS:如果有需要购买Xamarin安卓框架的可以联系我,分为原始框架和web嵌入框架两种,后者采用angularjs+web api技术,Web页面端实现MVVM :)】
以上全部是纯技术分析,当然不是全部,如有遗漏欢迎大家补充。
上面这些都是纯技术,是虚拟社会,回到现实世界,由于一些人是由初级程序员,尤甚者未入门的程序员,直接跳级到了架构师,或者高级程序员,从而引发代码世界的混乱,而这样的人才之所以成功,除了自身年龄和口才外,和那些非技术人才的力捧也是主因之一。不过呢,话说回来,我们是商业社会,有些项目能用即可,有些项目拖延到烂尾也是必要的,所以口才的重要性,并不比技术低。一个技术没入门的架构师并不比一个真才实学的架构差,即便他们其他技能也是零,因为我相信存在即是合理。