delegate(委托)是C#中一项令我比较费解的东西,在网上查到以下代码用以学习,根据MSDN中的说明,使用delegate可以让一个类(A)访问另一个类(B)的函数而不必是类(B)的成员.
在以下的代码中,在名称空间中定义了一个delegate对象vvCallBack(),它的参数就是准备要调用的目标函数(PrintSearchResult)的参数(string s). 这里注意,目标函数(PrintSearchResult)是一个private函数.
在类A中,通过第52行(public void SearchData(string SearchCondition, vvCallBack ClientDefinedProcedure))调用目标函数,这里无视目标函数是在其他哪个类中或者目标函数是不是public,只要在第58行中(ClientDefinedProcedure(i.Name);)用对参数即可
在类B中,第75行(vvCallBack procedure01 = new vvCallBack(PrintSearchResult);)把目标函数填入新建的delegate对象中,准备输入其他类中调用.
在第81行(lst.SearchData("Red", procedure01);)进行调用,由此,类B(MainClass)的PrintSearchResult函数通过delegate被类A(DataHolder)的函数调用了.
由此可见,在类B中,要使类A的成员返调类B的函数时,需要使用delegate.
总结一下使用delegate的步骤:
- delegate在使用前一定要先定义好,而且此定义必须要让类A和类B都能可见
- delegate定义时的参数要和目标函数的参数保持一致
- 需要的话,在调用类A中可以把此delegate对象当作参数,以备回调用
- 在要调用目标函数前,必须先声明一个delegate实例,即把目标函数填入此delegate对象中,基本语法:vvCallBack newDeleInstance = new vvCallBack(TargetFunctionNameWithoutParameter);
- 把此delegate实例当作参数,被类A的函数调用;此delegate也可以直接执行,如文末的例子一样,就用 newdeleInstance.Invoke();
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Collections;
- namespace DelegateStudy1
- {
- /**//*This is declaration of new data type "CallBack" which is based
- * on C# data type "delegate"*/
- public delegate void vvCallBack(string s);
- class
- {
- private string m_ObjectName;
- private string m_Color;
- public DataItem(string Name, string Color)
- {
- m_ObjectName = Name;
- m_Color = Color;
- }
- public string Name
- {get {return m_ObjectName;}}
- public string Color
- {get {return m_Color;}}
- }//Class Item
- /**//*This class represents collection of data items.*/
- class DataHolder
- {
- private ArrayList m_List;
- public DataHolder()
- {
- m_List = new ArrayList();
- m_List.Add(new DataItem("Desk", "Black"));
- m_List.Add(new DataItem("Car", "Red"));
- m_List.Add(new DataItem("Train", "Yellow"));
- m_List.Add(new DataItem("Tomato", "Red"));
- m_List.Add(new DataItem("Cheese", "Yellow"));
- m_List.Add(new DataItem("Computer","Grey"));
- m_List.Add(new DataItem("Sausage", "Red"));
- m_List.Add(new DataItem("Cat", "Black"));
- }
- /**//* this method provides search functionality for caller. When an item
- * meets search condition is found, client defined procedure activates.*/
- public void SearchData(string SearchCondition, vvCallBack ClientDefinedProcedure)
- {
- foreach (DataItem i in this.m_List)
- {
- if (i.Color == SearchCondition)
- {
- ClientDefinedProcedure(i.Name);
- }
- }
- }
- }//Class DataHolder
- class MainClass
- {
- [STAThread]
- static void Main(string[] args)
- {
- /**//*Create list of Data Items*/
- DataHolder lst = new DataHolder();
- /**//* Cteate instance of delegate with type CallBack and bind it
- * to user defined procedure PrintSearchResults()*/
- vvCallBack procedure01 = new vvCallBack(PrintSearchResult);
- Console.WriteLine("Red color objects:");
- /**//*Call search method with search critheria "Red" and user defined
- * procedure which is nesessary to execute when data item meets to search
- * creteria is found.*/
- lst.SearchData("Red", procedure01);
- Console.WriteLine("---------------");
- Console.ReadLine();
- }
- /**//*This procedure is called by DataHolder any time when data item meets to search
- * criteria is found.*/
- private static void PrintSearchResult(string s)
- {
- Console.WriteLine(s);
- }
- }//MainClass
- }
- public class Class1
- {
- public delegate int myFunction(int min);
- public int MyOtherFunction(int mer)
- {
- int mal = 4;
- return mer * mal;
- }
- public static void Main()
- {
- Class1 mb = new Class1();
- myFunction myD = new myFunction(mb.MyOtherFunction);
- int returnValue = myD.Invoke(8);
- console.WriteLine(returnValue);
- Console.Read();
- }
- }
DELPHI开发调用WEBSERVICE的一个简单例子,先转帖过来,代码还没有验证其正确性
原帖地址: http://kb.cnblogs.com/a/1505053/
========================================================
Webservice技术的出现将各种开发技术和语言完全的融合了,下面就这种融合在C#和delphi之间的交互做一次全面的体现
1.使用C#创建一个Webservice服务。
使用vs2005的模板创建C#的webservice非常容易。原文件如下:
[WebService(Namespace = "http://localhost/webserver/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class Service : System.Web.Services.WebService
{
public Service () {
//如果使用设计的组件,请取消注释以下行
InitializeComponent();
}
#region Component Designer generated code
private void InitializeComponent()
{
}
//Web 服务设计器所必需的
private IContainer components = null;
protected override void Dispose(bool disposing)
{
if (disposing && components != null)
{
components.Dispose();
}
base.Dispose(disposing);
}
#endregion
//这个是自动生成的一个webservice函数,可以不要。
[WebMethod]
public string HelloWorld() {
return "Hello World";
}
//这个才是我们自己创建的,
[WebMethod]
public int addnumber(int a, int b)
{
return = a + b;
}
}
2.使用delphi创建一个dll(非com的dll),该dll调用上面的webserivce服务。
使用delphi调用C#的webservice过程也很容易,但是对于新手可能比较麻烦(我就是这么过来的)
第一步:创建一个dll单元:
{$R *.res}
function GetNum(a,b:integer):integer stdcall; [Page]
var
ireturn :Integer;
begin
ireturn:=GetServiceSoap().addnumber(a,b); //这个GetServiceSoap是什么,看后面...
result:=ireturn;
end;
exports
GetNum name ’GetNum’;
begin
end.
//如果是delphi调用该dll必须使用下面的代码。C#调用则不需要了(C#还是要牛一些,呵呵)
initialization
coinitialize(nil);
finalization
counInitializ
第二步:将webserivce的WSDL导入到该dll工程中,如何导,方法至少有两种,我说简单的一种:
file->new->other->WebService->WSDL Importer,(将C#的WSDL输入)然后delphi会自动给你生成了一个pas文件,
function GetServiceSoap(UseWSDL: Boolean; Addr: string; HTTPRIO: THTTPRIO): ServiceSoap;
const
defWSDL = ’http://localhost/webserver/Service.asmx?WSDL’;
defURL = ’http://localhost/webserver/Service.asmx’;
defSvc = ’Service’;
defPrt = ’ServiceSoap’;
var
RIO: THTTPRIO;
begin
Result := nil;
if (Addr = ’’) then
begin
if UseWSDL then
Addr := defWSDL
else
Addr := defURL;
end;
if HTTPRIO = nil then
RIO := THTTPRIO.Create(nil)
else
RIO := HTTPRIO;
try
//RIO.HTTPWebNode.UseUTF8InHeader:=True; //在此添加一句,修改编码方案。
Result := (RIO as ServiceSoap);
if UseWSDL then
begin
RIO.WSDLLocation := Addr;
RIO.Service := defSvc;
RIO.Port := defPrt;
end else
RIO.URL := Addr;
finally
if (Result = nil) and (HTTPRIO = nil) then
RIO.Free;
end;
end;
initialization
InvRegistry.RegisterInterface(TypeInfo(ServiceSoap), ’http://localhost/webserver/’, ’utf-8’); [Page]
InvRegistry.RegisterDefaultSOAPAction(TypeInfo(ServiceSoap), ’http://localhost/webserver/%operationName%’);
//对于无法识别传入的参数的问题,需要手工加上这一句>......
InvRegistry.RegisterInvokeOptions(TypeInfo(ServiceSoap), ioDocument);
这段代码基本上你不用关心,但是,有两个地方需要特别注意:
1.RIO.HTTPWebNode.UseUTF8InHeader:=True;对于中文参数必须加上
2.InvRegistry.RegisterInvokeOptions(TypeInfo(ServiceSoap), ioDocument);
如果传入的参数不能被webservice识别时,多半是因为你没有加上这一句。
3.使用delphi调用上面的dll
就一个函数,没有什么好说的:
procedure TForm1.Button1Click(Sender: TObject);
type
GetNumTotal=function(a,b:integer):integer;stdcall;
var
Th:Thandle;
Tf:GetNumTotal;
Tp:TFarProc;
begin
Th:=LoadLibrary(’mywebservice.dll’); {装载DLL}
if Th>0 then
try
Tp:=GetProcAddress(Th,PChar(’GetNum’));
if Tp<>nil
then begin
Tf:=GetNumTotal(Tp);
Edit1.Text:=IntToStr(Tf(1,3)); {调用GetNumTotal函数}
end
else
ShowMessage(’GetNumTotal函数没有找到’);
finally
FreeLibrary(Th); {释放DLL}
end
else
ShowMessage(’mywebservice.dll没有找到’);
end;
4.使用C#调用上面的dll
[DllImport("mywebservice.dll", EntryPoint = "GetNum")]
public static extern int GetNum(int a, int b);
private void button1_Click(object sender, EventArgs e)
{
int a,b,i;
a=10;
b =20;
i=GetNum(a,b); //第一次比较慢(webserivce的唯一弊端!!!!)
textBox1.Text = i.ToString();
}
C#中每个类都可以独立存为XML并从对应XML文件中读取. 具体操作如下:
1. 每个类的声明之前,要加XmlRoot()声明XML文件的根节点,比如:
- [Serializable]
- [XmlRoot("DBRStream")]
- public class DBRStream
- {
- ...
- }
2. 对于每一个类的公共成员,要加上如下声明:
- [XmlAttribute("Phaseid")]
- public int Phaseid
- {
- set { phaseid = value; }
- get { return phaseid; }
- }
3. 如果此公共成员是复杂类型,比如说是一个数组集合,则用XmlArray声明:
但是要注意的是多维数组无法序列化,在此情况下,只能先用个内部变量List<>来对[,]进行转化以便进行存取。
- [XmlArray("Fractions")]
- [XmlArrayItem("Fraction")]
- public List<double> Fraction
- {
- set { fraction = value; }
- get { return fraction; }
- }
4. 如果此公共成员是另一个类,则声明如下:
- [XmlElement(typeof(dbrcomponentlist))]
- public dbrcomponentlist Complist
- {
- set { complist = value; }
- get { return complist; }
- }
5. 如果此公共成员不需要保存到XML文件,则声明如下:
- [XmlIgnoreAttribute]
- public StreamType streamtype;
6. 保存操作:
- public void Save(string filename)
- {
- System.IO.StreamWriter writer = new System.IO.StreamWriter(filename, false, System.Text.Encoding.UTF8);
- XmlSerializer ser = new XmlSerializer(GetType());
- ser.Serialize(writer,this);
- writer.Close();
- }
7. 读取操作:
- public classDBRCalc Load(string filename)
- {
- System.IO.StreamReader reader = new System.IO.StreamReader(filename);
- XmlSerializer ser = new XmlSerializer(typeof(classDBRCalc));
- classDBRCalc result = (classDBRCalc)ser.Deserialize(reader);
- reader.Close();
- return result;
- }
- }
前文"C#调用C++函数入口点的问题"说了一点关于使用DLLImport进行导入函数的事. C#调用C++的函数其实不止这一种方法, 还有一种方法是用delegate申明函数委托进行调用,这种方法略显麻烦,但是可以进行回调并应用指针.
在C#中,首先先要定义一个类,用来把DLL中函数地址转换成委托:
- public class DLLWrapper
- {
- ///<summary>
- /// API LoadLibrary
- ///</summary>
- [DllImport("Kernel32")]
- public static extern int LoadLibrary(String funcname);
- ///<summary>
- /// API GetProcAddress
- ///</summary>
- [DllImport("Kernel32")]
- public static extern int GetProcAddress(int handle, String funcname);
- ///<summary>
- /// API FreeLibrary
- ///</summary>
- [DllImport("Kernel32")]
- public static extern int FreeLibrary(int handle);
- ///<summary>
- ///通过非托管函数名转换为对应的委托, by jingzhongrong
- ///</summary>
- ///<param name="dllModule">Get DLL handle by LoadLibrary</param>
- ///<param name="functionName">Unmanaged function name</param>
- ///<param name="t">ManageR type对应的委托类型</param>
- ///<returns>委托实例,可强制转换为适当的委托类型</returns>
- public static Delegate GetFunctionAddress(int dllModule, string functionName, Type t)
- {
- int address = GetProcAddress(dllModule, functionName);
- if (address == 0)
- return null;
- else
- return Marshal.GetDelegateForFunctionPointer(new IntPtr(address), t);
- }
- ///<summary>
- ///将表示函数地址的IntPtr实例转换成对应的委托, by jingzhongrong
- ///</summary>
- public static Delegate GetDelegateFromIntPtr(IntPtr address, Type t)
- {
- if (address == IntPtr.Zero)
- return null;
- else
- return Marshal.GetDelegateForFunctionPointer(address, t);
- }
- ///<summary>
- ///将表示函数地址的int转换成对应的委托,by jingzhongrong
- ///</summary>
- public static Delegate GetDelegateFromIntPtr(int address, Type t)
- {
- if (address == 0)
- return null;
- else
- return Marshal.GetDelegateForFunctionPointer(new IntPtr(address), t);
- }
- }
然后, 用delegate声明函数:
- delegate void _amDBRSetThermoModel(int mid, ref int errid);
再然后, 自己写个private的函数封装DLL中的函数, hModule()函数的作用是取得DLL的地址,用在多个输出函数中
- private int hModule()
- {
- int _hModule = DLLWrapper.LoadLibrary(DLLPATH);
- if (_hModule == 0)
- {
- return 0;
- }
- return _hModule;
- }
- private void amDBRInitialize()
- {
- try
- {
- _amDBRInitialize amf = (_amDBRInitialize)DLLWrapper.GetFunctionAddress(hModule(), "amDBRInitialize", typeof(_amDBRInitialize));
- amf();
- }
- catch (Exception e)
- {
- throw e;
- }
- }
C++编写的DLL函数被C#所写的应用程序调用, 使用VS2005进行DEBUG时, 所设的断点无效, 系统信息显示"The breakpoint will not currently be hit. No symbols have been loaded for this document."

查阅无数资料, 大多写的是关于PDB文件如何如何, 试过都没有作用.
后来发现,其实只要在project properties中更改一下debugger type 就可以了. 如下图所示, 把debugger type从AUTO改到MIXED, 断点就可以用了, 不过要注意改完并DEBUG刚开始时, 断点还是空心的, 只有当DLL被调用时, 断点标记才会变成实心并被激活.






