Jan 5

delegate初探 不指定

kcao , 15:12 , 技术 , 评论(0) , 引用(0) , 阅读(1359) , Via 本站原创

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的步骤:

  1. delegate在使用前一定要先定义好,而且此定义必须要让类A和类B都能可见
  2. delegate定义时的参数要和目标函数的参数保持一致
  3. 需要的话,在调用类A中可以把此delegate对象当作参数,以备回调用
  4. 在要调用目标函数前,必须先声明一个delegate实例,即把目标函数填入此delegate对象中,基本语法:vvCallBack newDeleInstance = new vvCallBack(TargetFunctionNameWithoutParameter);
  5. 把此delegate实例当作参数,被类A的函数调用;此delegate也可以直接执行,如文末的例子一样,就用 newdeleInstance.Invoke();

 

C# 代码复制内容到剪贴板
  1. using System;    
  2. using System.Collections.Generic;    
  3. using System.Text;    
  4. using System.Collections;    
  5.      
  6. namespace DelegateStudy1    
  7. {    
  8. /**//*This is declaration of new data type "CallBack" which is based   
  9. * on C# data type "delegate"*/    
  10. public delegate void vvCallBack(string s);    
  11.      
  12. class    
  13. {    
  14. private string m_ObjectName;    
  15. private string m_Color;    
  16.      
  17. public DataItem(string Name, string Color)    
  18. {    
  19. m_ObjectName = Name;    
  20. m_Color = Color;    
  21. }    
  22.      
  23. public string Name    
  24. {get {return m_ObjectName;}}    
  25.      
  26. public string Color    
  27. {get {return m_Color;}}    
  28.      
  29. }//Class Item    
  30.      
  31.      
  32. /**//*This class represents collection of data items.*/    
  33. class DataHolder    
  34. {    
  35. private ArrayList m_List;    
  36.      
  37. public DataHolder()    
  38. {    
  39. m_List = new ArrayList();    
  40. m_List.Add(new DataItem("Desk""Black"));    
  41. m_List.Add(new DataItem("Car""Red"));    
  42. m_List.Add(new DataItem("Train""Yellow"));    
  43. m_List.Add(new DataItem("Tomato""Red"));    
  44. m_List.Add(new DataItem("Cheese""Yellow"));    
  45. m_List.Add(new DataItem("Computer","Grey"));    
  46. m_List.Add(new DataItem("Sausage""Red"));    
  47. m_List.Add(new DataItem("Cat""Black"));    
  48. }    
  49.      
  50. /**//* this method provides search functionality for caller. When an item   
  51. * meets search condition is found, client defined procedure activates.*/    
  52. public void SearchData(string SearchCondition, vvCallBack ClientDefinedProcedure)    
  53. {    
  54. foreach (DataItem i in this.m_List)    
  55. {    
  56. if (i.Color == SearchCondition)    
  57. {    
  58. ClientDefinedProcedure(i.Name);    
  59. }    
  60. }    
  61. }    
  62. }//Class DataHolder    
  63.      
  64.      
  65. class MainClass    
  66. {    
  67. [STAThread]    
  68. static void Main(string[] args)    
  69. {    
  70. /**//*Create list of Data Items*/    
  71. DataHolder lst = new DataHolder();    
  72.      
  73. /**//* Cteate instance of delegate with type CallBack and bind it   
  74. * to user defined procedure PrintSearchResults()*/    
  75. vvCallBack procedure01 = new vvCallBack(PrintSearchResult);    
  76.      
  77. Console.WriteLine("Red color objects:");    
  78. /**//*Call search method with search critheria "Red" and user defined   
  79. * procedure which is nesessary to execute when data item meets to search   
  80. * creteria is found.*/    
  81. lst.SearchData("Red", procedure01);    
  82. Console.WriteLine("---------------");    
  83. Console.ReadLine();    
  84.      
  85. }    
  86.      
  87. /**//*This procedure is called by DataHolder any time when data item meets to search   
  88. * criteria is found.*/    
  89. private static void PrintSearchResult(string s)    
  90. {    
  91. Console.WriteLine(s);    
  92. }    
  93. }//MainClass    
  94.      
  95. }    

 

C# 代码复制内容到剪贴板
  1. public class Class1    
  2. {    
  3. public delegate int myFunction(int min);    
  4. public int MyOtherFunction(int mer)    
  5. {    
  6. int mal = 4;    
  7. return mer * mal;    
  8. }    
  9.      
  10. public static void Main()    
  11. {    
  12. Class1 mb = new Class1();    
  13. myFunction myD = new myFunction(mb.MyOtherFunction);    
  14. int returnValue = myD.Invoke(8);    
  15. console.WriteLine(returnValue);    
  16. Console.Read();    
  17. }    
  18. }    

 

Tags: , , ,
Dec 16

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();
}

Tags: , , ,
Dec 14

C#中每个类都可以独立存为XML并从对应XML文件中读取. 具体操作如下:

1. 每个类的声明之前,要加XmlRoot()声明XML文件的根节点,比如:

C# Code Copy Code To Clipboard
  1. [Serializable]
  2. [XmlRoot("DBRStream")]
  3. public class DBRStream
  4. {
  5. ...
  6. }

2. 对于每一个类的公共成员,要加上如下声明:

C# Code Copy Code To Clipboard
  1. [XmlAttribute("Phaseid")]
  2. public int Phaseid
  3. {
  4. set { phaseid = value; }
  5. get { return phaseid; }
  6. }

3. 如果此公共成员是复杂类型,比如说是一个数组集合,则用XmlArray声明:

但是要注意的是多维数组无法序列化,在此情况下,只能先用个内部变量List<>来对[,]进行转化以便进行存取。

C# Code Copy Code To Clipboard
  1. [XmlArray("Fractions")]
  2. [XmlArrayItem("Fraction")]
  3. public List<double> Fraction
  4. {
  5. set { fraction = value; }
  6. get { return fraction; }
  7. }

4. 如果此公共成员是另一个类,则声明如下:

C# Code Copy Code To Clipboard
  1. [XmlElement(typeof(dbrcomponentlist))]
  2. public dbrcomponentlist Complist
  3. {
  4. set { complist = value; }
  5. get { return complist; }
  6. }

5. 如果此公共成员不需要保存到XML文件,则声明如下:

C# Code Copy Code To Clipboard
  1. [XmlIgnoreAttribute]
  2. public StreamType streamtype;

6. 保存操作:

C# Code Copy Code To Clipboard
  1. public void Save(string filename)
  2. {
  3. System.IO.StreamWriter writer = new System.IO.StreamWriter(filename, false, System.Text.Encoding.UTF8);
  4. XmlSerializer ser = new XmlSerializer(GetType());
  5. ser.Serialize(writer,this);
  6. writer.Close();
  7. }

7. 读取操作:

C# Code Copy Code To Clipboard
  1. public classDBRCalc Load(string filename)
  2. {
  3. System.IO.StreamReader reader = new System.IO.StreamReader(filename);
  4. XmlSerializer ser = new XmlSerializer(typeof(classDBRCalc));
  5. classDBRCalc result = (classDBRCalc)ser.Deserialize(reader);
  6. reader.Close();
  7. return result;
  8. }
  9. }

 

Tags: ,
Dec 2

前文"C#调用C++函数入口点的问题"说了一点关于使用DLLImport进行导入函数的事. C#调用C++的函数其实不止这一种方法, 还有一种方法是用delegate申明函数委托进行调用,这种方法略显麻烦,但是可以进行回调并应用指针.

在C#中,首先先要定义一个类,用来把DLL中函数地址转换成委托:

HiddenCopy Code To Clipboard
  1. public class DLLWrapper
  2. {
  3. ///<summary>
  4. /// API LoadLibrary
  5. ///</summary>
  6. [DllImport("Kernel32")]
  7. public static extern int LoadLibrary(String funcname);
  8.  
  9. ///<summary>
  10. /// API GetProcAddress
  11. ///</summary>
  12. [DllImport("Kernel32")]
  13. public static extern int GetProcAddress(int handle, String funcname);
  14.  
  15. ///<summary>
  16. /// API FreeLibrary
  17. ///</summary>
  18. [DllImport("Kernel32")]
  19. public static extern int FreeLibrary(int handle);
  20.  
  21. ///<summary>
  22. ///通过非托管函数名转换为对应的委托, by jingzhongrong
  23. ///</summary>
  24. ///<param name="dllModule">Get DLL handle by LoadLibrary</param>
  25. ///<param name="functionName">Unmanaged function name</param>
  26. ///<param name="t">ManageR type对应的委托类型</param>
  27. ///<returns>委托实例,可强制转换为适当的委托类型</returns>
  28. public static Delegate GetFunctionAddress(int dllModule, string functionName, Type t)
  29. {
  30. int address = GetProcAddress(dllModule, functionName);
  31. if (address == 0)
  32. return null;
  33. else
  34. return Marshal.GetDelegateForFunctionPointer(new IntPtr(address), t);
  35. }
  36.  
  37. ///<summary>
  38. ///将表示函数地址的IntPtr实例转换成对应的委托, by jingzhongrong
  39. ///</summary>
  40. public static Delegate GetDelegateFromIntPtr(IntPtr address, Type t)
  41. {
  42. if (address == IntPtr.Zero)
  43. return null;
  44. else
  45. return Marshal.GetDelegateForFunctionPointer(address, t);
  46. }
  47.  
  48. ///<summary>
  49. ///将表示函数地址的int转换成对应的委托,by jingzhongrong
  50. ///</summary>
  51. public static Delegate GetDelegateFromIntPtr(int address, Type t)
  52. {
  53. if (address == 0)
  54. return null;
  55. else
  56. return Marshal.GetDelegateForFunctionPointer(new IntPtr(address), t);
  57. }
  58. }

然后, 用delegate声明函数:

HiddenCopy Code To Clipboard
  1. delegate void _amDBRSetThermoModel(int mid, ref int errid);

再然后, 自己写个private的函数封装DLL中的函数, hModule()函数的作用是取得DLL的地址,用在多个输出函数中

HiddenCopy Code To Clipboard
  1. private int hModule()
  2. {
  3. int _hModule = DLLWrapper.LoadLibrary(DLLPATH);
  4. if (_hModule == 0)
  5. {
  6. return 0;
  7. }
  8. return _hModule;
  9. }
  10.  
  11. private void amDBRInitialize()
  12. {
  13. try
  14. {
  15. _amDBRInitialize amf = (_amDBRInitialize)DLLWrapper.GetFunctionAddress(hModule(), "amDBRInitialize", typeof(_amDBRInitialize));
  16. amf();
  17. }
  18. catch (Exception e)
  19. {
  20. throw e;
  21. }
  22. }

 

Tags: , , , ,
Dec 2

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被调用时, 断点标记才会变成实心并被激活.

Tags: , , ,
分页: 5/6 第一页 上页 1 2 3 4 5 6 下页 最后页 [ 显示模式: 摘要 | 列表 ]