封装定义为"把一个或多个项目封闭在一个物理的或者逻辑的包中",这个包就是类。在面向对象程序设计方法论中,封装可以防止对实现细节的访问。
具有相同特征、行为,是一类事物的抽象
类是对象的模板,通过类创建对象
//声明在namespace中
/*class 类名
{
//成员变量 表示特征
//成员方法 表示行为
//成员属性 保护成员变量
//构造函数和析构函数 初始化和释放
//索引器 像数组一样使用
//运算符重载 自定义对象可计算
//静态成员 类名.点出成员使用
}*/
class Person
{
}
类声明和类对象声明是两个概念:
//类名 变量名;
//类名 变量名 = null;
//类名 变量名 = new 类名();
Person p1;
Person p2 = null;//空,不分配堆的内存空间
//p3 p4虽然来自一个类的实例化对象,但它们的特征行为等都是分别独有的,不会相互共享
Person p3 = new Person();
Person p4 = new Person();
声明在类语句块中,来描述对象的特征,可以是任意的变量类型,数量无限制,是否赋值根据需求确定
enum E_SexType
{
Man,
Woman,
}
struct Position
{
}
class Pet//宠物类
{
}
class Person
{
//成员变量
public string name;
public int age;
public E_SexType sex;
//如果在类中声明和自己类型相同的成员变量时,不能对它实例化:Person grilFriend = new Person();
public Person grilFriend;//女朋友 类可以用自己,但结构体不能,因为类在初始化时候才会分配内存,结构体则会一直死循环
public Person[] friend;//朋友
public Position pos;//位置
public Pet pet = new Pet();//宠物
}
Person p = new Person();
/* 成员变量的使用和初始值
* 值类型、数字类型:默认为0
* bool类型:默认为false
* 引用类型:默认为null
* 用default(变量类型) 关键字可以看默认值
*/
Console.WriteLine(default(bool));
p.age = 10;
class Person
{
public string name;
public int age;
public Person[] friends;
//成员方法
public void Speak(string str)
{
Console.WriteLine($"{name}说{str}");
}
public bool isAudlt()
{
return age >= 18;
}
public void AddFriend(Person p)//添加朋友
{
if (friends == null)
{
friends = new Person[] { p };
}
else
{
Person[] newFriends = new Person[friends.Length + 1];
for(int i = 0; i < friends.Length; i++)//老朋友复制到新数组
{
newFriends[i] = friends[i];
}
newFriends[newFriends.Length - 1] = p;//新加的朋友
friends = newFriends;//地址重定向
}
}
必须实例化对象,再通过对象来使用,相当于对象执行了某个行为
Person p = new Person();
p.name = "abc";
p.age = 18;
p.Speak("123");
if (p.isAudlt()) p.Speak("我成年了");//使用
Person p2 = new Person();
p2.name = "def";
p2.age = 24;
p.AddFriend(p2);
foreach(Person f in p.friends)
{
Console.WriteLine(f.name);
}
class Person
{
public string name;
public int age;
//类中允许无参构造函数,结构体中不行
//无参构造函数
public Person()
{
name = "tyy";
age = 24;
}
//构造函数可以被重载,this代表当前调用该函数的对象本身
public Person(string name, int age)
{
this.name = name;
this.age = age;
}
//构造函数特殊写法:通过this 复用构造函数代码
//访问修饰符 构造函数名(参数):this(参数1,参数2...)。先调用this()里面的构造函数重载,再执行后面花括号内容
//先调用this()里面的构造函数重载,再执行后面花括号内容
public Person(string name):this()
{
Console.WriteLine("两个构造函数调用");
}
}
class Person
{
public Person()
{
}
~Person()
{
}
}
GC基本原理:
//手动出发垃圾回收的方法,一般在Loading切换场景时才调用
GC.Collect();
/*
访问修饰符 属性类型 属性名
{
get{} 读,写了get就一定要有一个返回值
set{} 写
}
*/
class Person
{
private string name;
private int age;
private int money;
private bool sex;
//属性的命名用帕斯卡命名法
public string Name
{
get
{
//可以在返回之前添加一些逻辑条件
return name;//虽然name是私有的,但是通过成员属性也能得到它
}
set
{
//可以在设置之前添加一些逻辑条件
//value关键字表示外部传入的值
name = value;
}
}
public int Money
{
get
{
//解密处理
return money - 5;
}
set
{
//可以进行额外的加密处理 起到安全和保密作用
if(value < 0)
{
value = 0;
Console.WriteLine("钱不能为负数");
}
money = value + 5;
}
}
}
Person p = new Person();
p.Name = "abc";//执行set{}
Console.WriteLine(p.Name);//p.Name执行get{}
p.Money = 1000;
Console.WriteLine(p.Money);//外部看是1000元,但在内存里面是1005元 起到了加密的作用
class Person
{
private string name;
private int age;
private int money;
private bool sex;
public bool Sex
{
get { return sex; }//创造只读属性,private类型的成员也能读
}
}
class Person
{
private string name;
private int age;
private int money;
private bool sex;
public float Height
{
get;
private set;
}
}
/*
element-type this[int index]
{
// get 访问器
get
{
// 返回 index 指定的值
}
// set 访问器
set
{
// 设置 index 指定的值
}
}
*/
class Person
{
private string name;
private int age;
private Person[] friends;
public Person this[int index]
{
//可以写逻辑条件来处理
get
{
if(friends == null || friends.Length - 1 < index)
{
return null;
}
return friends[index];
}
set
{
//和成员属性类似,value代表传入的值
if(friends == null)
{
friends = new Person[] { value };
}else if(index > friends.Length - 1)
{
friends[friends.Length - 1] = value;//举例 如果索引越界就把最后一个朋友顶掉
}
else friends[index] = value;
}
}
}
Person p = new Person();
p[0] = new Person();//调用set 得到1个朋友
Console.WriteLine(p[0]);//调用get
class Person
{
public int[,] array;
//函数名相同,但参数类型、个数或顺序不同
public int this[int i, int j]
{
get
{
return array[i, j];
}
set
{
array[i, j] = value;
}
}
}
class Test
{
//静态成员变量
public static float PI = 3.121592654f;
//成员变量
public int testInt = 100;
//静态成员方法
//静态方法不能使用非静态成员变量,与静态和非静态的生命周期有关
public static float CalcCircle(float r)
{
//πr²
return PI * r * r;
}
//普通成员方法
//非静态方法可以使用静态成员变量
public void testFun()
{
Console.WriteLine("123");
Console.WriteLine(PI);
}
}
Console.WriteLine(Test.PI);
Console.WriteLine(Test.CalcCircle(2));
//普通的只有new了对象之后才能使用那些变量方法等
Test t = new Test();
Console.WriteLine(t.testInt);
t.testFun();
相同点:都可以使用类名+点使用
不同点:
用 static 修饰的类,只能包含静态成员,不能被实例化
作用:
static class TestClass
{
public static int testIndex = 0;
public static void testFun()
{
}
}
static class StaticClass
{
//第一次使用类时,类里面的静态成员自动调用一次
public static int testInt = 100;
public static int testInt2 = 100;
static StaticClass()
{
Console.WriteLine("静态构造函数");
}
}
class Test
{
public static int testInt = 200;
static Test()
{
Console.WriteLine("静态构造");
}
public Test()
{
Console.WriteLine("普通构造");
}
}
Console.WriteLine(StaticClass.testInt);
//第一次使用类时,类里面的静态成员自动调用一次
Console.WriteLine(Test.testInt);
//普通构造在new的时候调用
Test t = new Test();
为现有 非静态 的 <变量类型> 添加新方法
作用:
特点:
访问修饰符 static 返回值 函数名(this 要拓展的类名 参数名,参数类型 参数名,......)
static class Tools
{
//为int拓展了一个成员方法,int里面是没有SpeakValue方法的
//value 代表使用该方法的 实例化对象
public static void SpeakValue(this int value)
{
//拓展方法的逻辑
Console.WriteLine("为int拓展的方法" + value);
}
public static void SpeakStringInfo(this string str, string str2, string str3)
{
Console.WriteLine("为string拓展的方法,调用方法的对象是:" + str);
Console.WriteLine("传的参数:" + str2 + str3);
}
//为自定义的类型Test拓展方法
public static void Fun3(this Test t)
{
Console.WriteLine("为Test拓展的方法");
}
}
class Test
{
public int i = 10;
public void Fun1()
{
Console.WriteLine("123");
}
public void Fun2()
{
Console.WriteLine("456");
}
}
int i = 10;
i.SpeakValue();
string s = "ABC";
s.SpeakStringInfo("a ", "b");
Test t = new Test();
t.Fun3();
作用:让自定义的类和结构体能够使用运算符进行运算,关键字 operator
特点:
注意:
注意:运算符需要两个参数还是一个参数
可重载的:
不可重载的:
public static 返回类型 operator 运算符(参数列表)
class Point
{
public int x;
public int y;
//重载‘+’成为类Point的加法
public static Point operator +(Point p1, Point p2)
{
Point p = new Point();
p.x = p1.x + p2.x;
p.y = p1.y + p2.y;
return p;
}
//可以有多个重载
public static Point operator +(Point p1, int value)
{
Point p = new Point();
p.x = p1.x + value;
p.y = p1.y + value;
return p;
}
}
Point p1 = new Point();
p1.x = 1;
p1.y = 1;
Point p2 = new Point();
p2.x = 2;
p2.y = 2;
Point p3 = p1 + p2;
Point p4 = p3 + 2;
class Person
{
public int age;
public string name;
public Body body;
public class Body
{
Arm leftArm;
Arm rightArm;
class Arm
{
}
}
}
//使用
Person p = new Person();
Person.Body body = new Person.Body();
把一个类分成几部分申明。
作用:分部描述一个类,增加程序的拓展性,关键字 partial
将方法的声明和实现分离。
特点:
//分部类
partial class Student
{
public string name;
public bool sex;
//分部方法
partial void Move();
}
partial class Student
{
public int number;
partial void Move()
{
//实现分部方法逻辑
throw new NotImplementedException();
}
public void Speak(string str)
{
}
}
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev
我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss
好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信
如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象
我在Rails工作并有以下类(class):classPlayer当我运行时bundleexecrailsconsole然后尝试:a=Player.new("me",5.0,"UCLA")我回来了:=>#我不知道为什么Player对象不会在这里初始化。关于可能导致此问题的操作/解释的任何建议?谢谢,马里奥格 最佳答案 havenoideawhythePlayerobjectwouldn'tbeinitializedhere它没有初始化很简单,因为你还没有初始化它!您已经覆盖了ActiveRecord::Base初始化方法,但您没有调
我有一个服务模型/表及其注册表。在表单中,我几乎拥有服务的所有字段,但我想在验证服务对象之前自动设置其中一些值。示例:--服务Controller#创建Action:defcreate@service=Service.new@service_form=ServiceFormObject.new(@service)@service_form.validate(params[:service_form_object])and@service_form.saverespond_with(@service_form,location:admin_services_path)end在验证@ser
如何在ruby中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL
我想让一个yaml对象引用另一个,如下所示:intro:"Hello,dearuser."registration:$introThanksforregistering!new_message:$introYouhaveanewmessage!上面的语法只是它如何工作的一个例子(这也是它在thiscpanmodule中的工作方式。)我正在使用标准的rubyyaml解析器。这可能吗? 最佳答案 一些yaml对象确实引用了其他对象:irb>require'yaml'#=>trueirb>str="hello"#=>"hello"ir
假设我有一个FireNinja我的数据库中的对象,使用单表继承存储。后来才知道他真的是WaterNinja.将他更改为不同的子类的最干净的方法是什么?更好的是,我很想创建一个新的WaterNinja对象并替换旧的FireNinja在数据库中,保留ID。编辑我知道如何创建新的WaterNinja来self现有FireNinja的对象,我也知道我可以删除旧的并保存新的。我想做的是改变现有项目的类别。我是通过创建一个新对象并执行一些ActiveRecord魔法来替换行,还是通过对对象本身做一些疯狂的事情,或者甚至通过删除它并使用相同的ID重新插入来做到这一点,这是问题的一部分。