2010-03-23 00:21:00 mousebaby808 阅读数 1665
  • 面向对象C#初级入门精讲(5)面向对象

    面向对象C#初级入门精讲视频教程,该课程内容涵盖1、类的继承,包括理解继承的概念、存在继承关系的构造方法执行过程、隐藏基类的方法、装箱与拆箱、sealed关键字的作用2、多态的实现,包括重写父类方法、多态的实现、base关键字、里氏转换原则及Object类3、抽象类与接口的使用4、异常的处理方法,包括try……catch和finally5、理解命名空间的含义6、程序集的意义及其应用7、理解C#7.0的9个新特性

    1115 人正在学习 去看看 徐照兴

  在C#中,有一个特殊的类型Object类。这个类是C#中所有其它类的超类。

  我们知道,C#只允许单继承,也即每一个类都可以有唯一的一个超类。本章我们重新定义:所有的C#类有且只有一个超类。如果一个类没有显式指定,则C#以Object类作为其超类。所以所有的类都会直接或者间接的继承Object类。

  定义Object类的作用:

  1、向所有的类引入一些关键方法;
  2、可以让任意类的对象都引用到Object类型的变量上。


  我们先看”作用1“

  Object类包含了若干方法,如下图:

 
图1

  • Object构造器,默认构造器而已,没啥特点;
  • ~Object方法,析构器,这玩意儿我们讲到IO操作的时候讲,挺麻烦的,比C++的析构函数啰嗦多了;
  • Equals方法,用于比较对象,该方法有一个静态重载,该方法很重要;
  • GetHashCode方法,该方法用于获取一个对象的Hash值,讲到集合类的时候讲;
  • GetType方法,获取一个对象的反射对象,讲反射的时候讲;
  • MemberwiseClone方法,返回一个当前对象的拷贝(浅拷贝);
  • ReferenceEquals方法,一个静态方法,用来比较两个对象的引用;
  • ToString方法,返回对象的字符串表示。

  上述的这一系列方法会被继承到所有类中,即所有的C#对象都具有这一系列方法。


对象比较

  我们研究过,在C#中,存在两种类型的对象——值类型对象和引用类型对象,分别对应两种类型的变量:值类型变量和引用类型变量,和C语言的值类型变量及指针类型变量对应。

  我们可以简单的理解为:值类型变量保存着对象的“值”,而引用类型对象保存这对象的“引用”;所以在C#中,变量的比较就有两种含义。

  1. 对于值类型变量来说,比较两个变量是否保存着相同的值;
  2. 对于引用类型变量来所,比较两个变量是否引用到了同一个对象上。

  当然,特殊情况下,我们也可能需要比较两个引用类型变量所引用的对象是否具有相同值的属性。我们看代码:

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

namespace Edu.Study.OO.Equals {
	/// <summary>
	/// 定义一个引用类型,实现ICloneable接口
	/// </summary>
	public class IntegerValue : ICloneable {
		/// <summary>
		/// 保存值的字段
		/// </summary>
		private int value;
	
		/// <summary>
		/// 构造器
		/// </summary>
		public IntegerValue() {
			this.value = 0;
		}
	
		/// <summary>
		/// 参数构造器
		/// </summary>
		public IntegerValue(int value) {
			this.Value = value;
		}
	
		/// <summary>
		/// Value属性
		/// </summary>
		public int Value {
			get {
				return this.value;
			}
			set {
				this.value = value;
			}
		}
	
		/// <summary>
		/// 实现ICloneable接口,返回当前对象的副本
		/// </summary>
		public Object Clone() {
			// MemberwiseClone方法,返回当前对象的副本
			return base.MemberwiseClone();
		}
	}
	
	
	class Program {
		static void Main(string[] args) {
			// 声明变量iv1,引用到IntegerValue的实例上
			IntegerValue iv1 = new IntegerValue(100);
		
			// 声明变量iv2,保存iv1中的引用
			IntegerValue iv2 = iv1;

			// 使用==运算符比较iv1和iv2变量
			Console.WriteLine("iv1和iv2{0}", iv1 == iv2 ? "相同" : "不同");

			// 调用Clone方法获取iv1变量所引用的对象的副本,返回的引用保存在变量iv2中
			iv2 = (IntegerValue)iv1.Clone();

			// 使用==运算符比较iv1和iv2变量
			Console.WriteLine("iv1和iv2{0}", iv1 == iv2 ? "相同" : "不同");

			iv2 = iv1;

			// 使用Equals方法重新比较对象
			Console.WriteLine("iv1和iv2{0}", iv1.Equals(iv2) ? "相同" : "不同");

			iv2 = (IntegerValue)iv1.Clone();
			Console.WriteLine("iv1和iv2{0}", iv1.Equals(iv2) ? "相同" : "不同");
		}
	}
}

  上述这段代码有如下几个要点需要注意:

  • 对于引用类型,=运算符将引用从一个变量传递到另一个变量,所以=两边的变量引用同一个对象;
  • 对于引用相同的两个变量,使用==运算符返回true;
  • 对象的Clone方法产生一个新实例,返回该实例的引用,该实例的所有字段值和原对象相同,即Clone方法得到对象的一个副本。从Object类继承下来的保护方法MemberwiseClone返回当前对象的副本;
  • 对于Clone方法返回的对象,其引用和原对象不同,==运算符返回false;
  • 从Object继承下来的Equals方法结果和==运算符相同,只是比较当前引用(this)和参数保存的引用是否引用到了同一个对象上。

  我们修改一下上面的代码,增加一个新方法:

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

namespace Edu.Study.OO.Equals {
	/// <summary>
	/// 定义一个引用类型,实现ICloneable接口
	/// </summary>
	public class IntegerValue : ICloneable {
		/// <summary>
		/// 保存值的字段
		/// </summary>
		private int value;

		/// <summary>
		/// 构造器
		/// </summary>
		public IntegerValue() {
			this.value = 0;
		}

		/// <summary>
		/// 参数构造器
		/// </summary>
		public IntegerValue(int value) {
			this.Value = value;
		}

		/// <summary>
		/// Value属性
		/// </summary>
		public int Value {
			get {
				return this.value;
			}
			set {
				this.value = value;
			}
		}

		/// <summary>
		/// 覆盖Object类Equals方法
		/// </summary>
		/// <param name="obj">待比较的对象</param>
		/// <returns>对象obj和当前对象是否相同</returns>
		public override bool Equals(object obj) {
			bool isEquals = Object.ReferenceEquals(obj, this);
			if (isEquals == false) {
				IntegerValue iv = obj as IntegerValue;
				if (iv != null) {
					isEquals = iv.value == this.value;
				}
			}
			return isEquals;
		}

		/// <summary>
		/// 实现ICloneable接口,返回当前对象的副本
		/// </summary>
		public Object Clone() {
			// MemberwiseClone方法,返回当前对象的副本
			return base.MemberwiseClone();
		}
	}

	
	class Program {
		static void Main(string[] args) {
			// 声明变量iv1,引用到IntegerValue的实例上
			IntegerValue iv1 = new IntegerValue(100);

			// 声明变量iv2,保存iv1中的引用
			IntegerValue iv2 = iv1;

			// 使用==运算符比较iv1和iv2变量
			Console.WriteLine("iv1和iv2{0}", iv1 == iv2 ? "相同" : "不同");

			// 调用Clone方法获取iv1变量所引用的对象的副本,返回的引用保存在变量iv2中
			iv2 = (IntegerValue)iv1.Clone();

			// 使用==运算符比较iv1和iv2变量
			Console.WriteLine("iv1和iv2{0}", iv1 == iv2 ? "相同" : "不同");

			iv2 = iv1;

			// 由于覆盖了Equals方法,使用Equals方法得到了与==运算符不同的结果
			Console.WriteLine("iv1和iv2{0}", iv1.Equals(iv2) ? "相同" : "不同");

			iv2 = (IntegerValue)iv1.Clone();
			Console.WriteLine("iv1和iv2{0}", iv1.Equals(iv2) ? "相同" : "不同");
		}
	}
}

  这次我们覆盖了Equals方法,程序运行结果则不同了:Equals不再比较两个变量保存的对象引用是否相同,而是比较两个变量所引用的对象是否具有相同的属性值。

  我们看一下覆盖后Equals方法的具体执行流程:

  1. 使用Object静态方法ReferenceEquals比较参数obj和当前对象引用(this)是否相同,如果引用相同,则必为相同对象;
  2. 如果变量obj和当前引用不相同,则使用as运算符,尝试将obj类型转换和当前对象相同的类型,转换成功表示obj变量引用着和当前对象类相同的对象,as运算符转换后对象的引用,否则返回null,只有同类型的对象才需要比较,不同类型的对象必然是不同的对象;
  3. 如果as运算符转换对象成功,则进一步比较当前对象引用(this)和参数obj引用对象的字段值是否相等

  好了,总结一下:==和Object类的Equals方法都是比较对象的引用是否相同,并不比较对象的字段是否相等;而Equals方法可以覆盖,以求让其对对象的字段进行等值比较。

  所以,如果需要比较两个C#引用类型变量,除非确定需要比较的就是对象引用时才可以使用==运算符,否则应该使用对象的Equals方法,以防对象所属的类覆盖了这个方法

  说完引用类型,值类型是什么样呢?

  C#令所有的值类型从一个特殊的ValueType类继承(这也直接解释了为什么值类型只能实现接口而无法继承其它类,值类型已经自动继承了一个类),我们看一下ValueType的特点:


图2

  从图中可以看到,ValueType已经覆盖了Equals方法,即从ValueType继承的类型,不再遵守Object类定义的Equals方法。

  从前面的代码中,我们得知,Object类的Equals方法仅仅是比较了当前引用和参数所引用对象的引用是否相同,从前面的课程我们也学习到,值类型对象不存在引用的。所以ValueType覆盖了Equals方法,令所有的值类型对象在调用Equals方法时,比较的是两个对象的所有字段值是否相等

  一般情况下,我们无需覆盖Equals方法。对于引用类型来说,等值比较就是比较对象的引用,引用不同的两个对象应该就是不同的对象;对于值类型来说,比较的就是所有字段的值,字段值不同的两个对象是不同的对象。

  只有在特殊情况下,才需要覆盖Equals方法,已定义某个类特殊的对象比较方法。

  注意:理论上可以用任意代码覆盖Equals方法,但要保证如下原则:

  • 合理性:Equals只能用于对象比较,不能做其它任何用途;
  • 稳定性:对于两个已存在的对象,在对象未作任何改变的情况下,无论任何时候调用Equals方法,返回的结果应该是一样的;
  • 对称性:对于对象a和b,则a.Equalse(b)和b.Equals(a)返回的结果应该是一样的。

  一旦覆盖了Equals方法,则C#推荐同时覆盖GetHashCode方法,具体原因讲到集合类是再做详细说明。


对象的字符串表示

  可以覆盖ToString方法,来返回某个对象的字符串表示。

  Object类的ToString方法返回一个对象所属类的类名。我们可以在任何类中覆盖ToString方法以返回需要的字符串。看代码:

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

namespace Edu.Study.OO.Equals {
	/// <summary>
	/// 定义一个引用类型,实现ICloneable接口
	/// </summary>
	public class IntegerValue : ICloneable {
		private int value;

		/// <summary>
		/// 构造器
		/// </summary>
		public IntegerValue() {
			this.value = 0;
		}

		/// <summary>
		/// 参数构造器
		/// </summary>
		public IntegerValue(int value) {
			this.Value = value;
		}

		/// <summary>
		/// Value属性
		/// </summary>
		public int Value {
			get {
				return this.value;
			}
			set {
				this.value = value;
			}
		}

		/// <summary>
		/// 实现ICloneable接口,返回当前对象的副本
		/// </summary>
		public Object Clone() {
			// MemberwiseClone方法,返回当前对象的副本
			return base.MemberwiseClone();
		}
	}

	class Program {
		static void Main(string[] args) {
		IntegerValue iv = new IntegerValue(100);
		Console.WriteLine(iv.ToString());
		}
	}
}

  和下面这段代码做一个比较,看看结果有何不同:

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

namespace Edu.Study.OO.Equals {
	/// <summary>
	/// 定义一个引用类型,实现ICloneable接口
	/// </summary>
	public class IntegerValue : ICloneable {
		/// <summary>
		/// 保存值的字段
		/// </summary>
		private int value;

		/// <summary>
		/// 构造器
		/// </summary>
		public IntegerValue() {
			this.value = 0;
		}

		/// <summary>
		/// 参数构造器
		/// </summary>
		public IntegerValue(int value) {
			this.Value = value;
		}

		/// <summary>
		/// Value属性
		/// </summary>
		public int Value {
			get {
				return this.value;
			}
			set {
				this.value = value;
			}
		}

		/// <summary>
		/// 实现ICloneable接口,返回当前对象的副本
		/// </summary>
		public Object Clone() {
			// MemberwiseClone方法,返回当前对象的副本
			return base.MemberwiseClone();
		}

		/// <summary>
		/// 获取对象的字符串表达
		/// </summary>
		public override string ToString() {
			return this.value.ToString();
		}
	}

	class Program {
		static void Main(string[] args) {
			IntegerValue iv = new IntegerValue(100);
			Console.WriteLine(iv1.ToString());
		}
	}
}

  将ToString方法改为如下表示,再看看结果:

public override string ToString() {
	return "Hello World";
}

  可以看到,ToString方法理论上也可以用任意代码覆盖,但应该返回符合对象含义的字符串。

2018-02-02 18:14:45 a_dev 阅读数 3162
  • 面向对象C#初级入门精讲(5)面向对象

    面向对象C#初级入门精讲视频教程,该课程内容涵盖1、类的继承,包括理解继承的概念、存在继承关系的构造方法执行过程、隐藏基类的方法、装箱与拆箱、sealed关键字的作用2、多态的实现,包括重写父类方法、多态的实现、base关键字、里氏转换原则及Object类3、抽象类与接口的使用4、异常的处理方法,包括try……catch和finally5、理解命名空间的含义6、程序集的意义及其应用7、理解C#7.0的9个新特性

    1115 人正在学习 去看看 徐照兴

以object类型的对象返回其Shape属性为例。

        /// <summary>
        /// 返回Object对象的指定属性
        /// </summary>
        /// <param name="obj">传入的对象</param>
        /// <returns>返回的属性</returns>
        private GeoJSON.Net.Geometry.Point GetShape(object obj)
        {
            System.Reflection.PropertyInfo a = null;
            foreach (System.Reflection.PropertyInfo pi in obj.GetType().GetProperties())
            {
                if (pi.CanWrite)
                {
                    if (0 == string.Compare("Shape", pi.Name, true))
                    {
                        a = pi;
                        break;
                    }
                }
            }
            if (null == a)
            {
                return null;
            }
            return a.GetValue(obj) as GeoJSON.Net.Geometry.Point;
        }


2017-08-14 10:57:07 jbl20078 阅读数 476
  • 面向对象C#初级入门精讲(5)面向对象

    面向对象C#初级入门精讲视频教程,该课程内容涵盖1、类的继承,包括理解继承的概念、存在继承关系的构造方法执行过程、隐藏基类的方法、装箱与拆箱、sealed关键字的作用2、多态的实现,包括重写父类方法、多态的实现、base关键字、里氏转换原则及Object类3、抽象类与接口的使用4、异常的处理方法,包括try……catch和finally5、理解命名空间的含义6、程序集的意义及其应用7、理解C#7.0的9个新特性

    1115 人正在学习 去看看 徐照兴

今天用c#调用Object-C,写了一个入口方法:

//执行平台相关方法
    static const char*  callPlatformFunction(std::string functionName,std::string jsonContent);
调用方法
#if UNITY_IOS
		[DllImport("__Internal")]
		public static extern void callPlatformFunction(string __functionName,string __jsonContent);
	#endif

        Build Xcode工程报错:

dyld: Symbol not found: _GKPlayerAuthenticationDidChangeNotificationName
  Referenced from: /Users/ghgh/Library/Developer/CoreSimulator/Devices/E693C617-3C7F-4A07-991D-D6EB9C095BAE/data/Containers/Bundle/Application/0E5C0608-BAED-4D2C-823A-3A817F1707E2/myDemo.app/myDemo

问题具体原因可以参考:http://blog.sina.com.cn/s/blog_3e51bb390102vprj.html

        
        修改方式:平台接口定义修改为:

static const char*  callPlatformFunction(const char* functionName,const char* jsonContent);
补充:
    抱歉,根本原因是工程中未添加GameKit.framework

2014-01-02 17:50:40 u012085988 阅读数 10511
  • 面向对象C#初级入门精讲(5)面向对象

    面向对象C#初级入门精讲视频教程,该课程内容涵盖1、类的继承,包括理解继承的概念、存在继承关系的构造方法执行过程、隐藏基类的方法、装箱与拆箱、sealed关键字的作用2、多态的实现,包括重写父类方法、多态的实现、base关键字、里氏转换原则及Object类3、抽象类与接口的使用4、异常的处理方法,包括try……catch和finally5、理解命名空间的含义6、程序集的意义及其应用7、理解C#7.0的9个新特性

    1115 人正在学习 去看看 徐照兴

C/C++可以直接与object-c交互,只需把文件后缀写成.mm就行了。c#又可以和C/C++交互,所以嘛。。。c#也就可以和object-c交互了。


1、在unity中 c#调用object-c 函数

首先,定义一个新建一个.mm文件,然后在里面定义一个C风格接口的函数,如

extern "C"

{

void testFunc(char* arg)

{

// 这里可以调用object-c的函数了

// 如 [[ AlertView alloc] init]; ...

}

}

第二步,将这个mm文件放到unity工程的Assets/Plugins/IOS路径下。

第三步,声明C函数。c#脚本,调用上面的C接口,C函数里面又调用object-c的函数,最终就能达到c#调用object-c的目的。但是,如何C#中并没有testFunc这个函数,所以要先做函数声明。

unity若要编译ios项目,首先要导出xcode工程,然后再由xcode导出ipa安装包。当你生产xcode工程时,你会发现,第二步中的mm文件被引用到了xcdoe工程的Libraries下(你可以在xcdoe中的Libraries下找找看)。我的理解是这个mm文件最终会被编译成库,那上面的testFunc函数就成了库函数。在c#中要使用这个库函数,首先要在文件头加入using System.Runtime.InteropServices;然后声明函数:

[DllImort("__Internal")]

private static extern void testFunc(string arg);

  注意:这里的参数类型!!!是string而不是char*。关于C与C#参数类型映射关系,可以看这里 http://blog.csdn.net/yatusiter/article/details/9221861

第四步,调用函数。这时函数也在c#中声明过了,使用时就可以直接调用了。

代码如下:

extern "C"

{

    void test(char* title, char* msg, char* url)

    {

        NSString* nstitle = [[NSString alloc] initWithUTF8String:title];

        NSString* nsmsg = [[NSString alloc] initWithUTF8String:msg];

        NSString* nsurl = [[NSString alloc] initWithUTF8String:url];

        

        UIAlertView* view = [[UIAlertView alloc] initWithTitle:nstitle

                                                       message:nsmsg

                                                      delegate:nil

                                             cancelButtonTitle:NSLocalizedString(@"Close", nil)

                                             otherButtonTitles:nil];

        

        [view show];

    }

}
using UnityEngine;
using System.Collections;
using System.Runtime.InteropServices;
public class testscript : MonoBehaviour {

    // Use this for initialization
    void Start () {
    
    }
    
    // Update is called once per frame
    void Update () {
    
    }

    [DllImport("__Internal")]
    private static extern void test (string title, string msg, string url);

    void OnGUI()
    {
        if (GUI.Button (new Rect (100, 100, 100, 50), "test obj-c func")) {
            test ("omytitle", "omymsg", "omyurl");        
        }
    }
}

2、unity中 object-c 调用c#

UnitySendMessage("GameObjectName1", "MethodName1", "Message to send");

参数1:gameobject名字;参数2:回调函数的名字;参数3:参数。同android开发中java回调c#一样,三个参数都是字符串类型!但android开发中的第三个参数不能是null(若没有参数,可以用空字符串"",因为使用null程序会崩掉),这里不知道能不能为null,还没测试过。

2011-04-14 12:36:00 hyde114 阅读数 1162
  • 面向对象C#初级入门精讲(5)面向对象

    面向对象C#初级入门精讲视频教程,该课程内容涵盖1、类的继承,包括理解继承的概念、存在继承关系的构造方法执行过程、隐藏基类的方法、装箱与拆箱、sealed关键字的作用2、多态的实现,包括重写父类方法、多态的实现、base关键字、里氏转换原则及Object类3、抽象类与接口的使用4、异常的处理方法,包括try……catch和finally5、理解命名空间的含义6、程序集的意义及其应用7、理解C#7.0的9个新特性

    1115 人正在学习 去看看 徐照兴

要将C#object类型值转换成成有效的Json值,我们可以从这个命名空间中调用方法:
System.Web.Script.Serialization.JavaScriptSerializer,
它存在于.Net FrameWord 3.5框架中的System.Web.Extentions的DLL中.

我们在C#中使用它的序列话对象和反序列化对象.
下面是个快速对象:

一个简单的 Employee 实体类,

public class Employee
{
public string Name { get; set; }
public string Age { get; set; }
public string ID { get; set; }
}

添加一些对象到一个范型,

mployee oEmployee1 =  new Employee{Name="Pini",ID="111", Age="30"};

Employee oEmployee2 = new Employee { Name = "Yaniv", ID = "Cohen", Age = "31" };

Employee oEmployee3 = new Employee { Name = "Yoni", ID = "Biton", Age = "20" };

List<Employee> oList = new List<Employee>() { oEmployee1, oEmployee2, oEmployee3 };

这时我们转化这个范型:

System.Web.Script.Serialization.JavaScriptSerializer oSerializer = 
new System.Web.Script.Serialization.JavaScriptSerializer();

string
sJSON = oSerializer.Serialize(oList);

这时打印出的结果如下:

[{"Name":"Pini","Age":"30","ID":"111"},
{"Name":"Yaniv","Age":"31","ID":"Cohen"},
{"Name":"Yoni","Age":"20","ID":"Biton"}]

C#缺省参数

阅读数 1568

c# object to xml

阅读数 797

没有更多推荐了,返回首页