c# .net 常用的接口

(1) IComparable接口
IComparable接口定义通用的比较方法。由类型使用的IComparable接口提供了一种比较多个对象的标准方式。如果一个类要实现与其它对象的比较,则必须实现IComparable接口。由可以排序的类型,例如值类型实现以创建适合排序等目的类型特定的比较方法。
(2) IEnumerable接口
IEnumerable接口公开枚举数,该枚举数支持在集合上进行简单迭代。IEnumerable接口可由支持迭代内容对象的类实现。
(3) IEnumerator接口
IEnumerator接口支持在集合上进行简单迭代。是所有枚举数的基接口。
枚举数只允许读取集合中的数据,枚举数无法用于修改基础集合。
(4) ICollection接口
ICollection接口定义所有集合的大小、枚举数和同步方法。ICollection接口是System.Collections命名空间中类的基接口。
(5) IDictionary接口
IDictionary接口是基于ICollection接口的更专用的接口。IDictionary 实现是键/值对的集合,如Hashtable类。
(6) IList接口

IList接口实现是可被排序且可按照索引访问其成员的值的集合,如ArrayList类。


(*) 接口也可以继承接口,但子接口不提供父接口方法的实现

 

(*) 当一个类同时继承父类又实现接口,要把接口放在最后面,如class xxx : ParentClass, ISomeInterface

 

(*) 当同时实现的多个接口中出现同名方法

除了解决同名方法冲突,此段代码同时展示了3种使用接口的方式:

复制代码
public   interface  IDraw
{
    
void  Draw();
}

public   interface  IDraw3D
{
    
void  Draw();
}

public   class  Image : IDraw, IDraw3D
{
    
// public void IDraw.Draw()   Error! 加任何访问修饰符都会有编译错误
     void  IDraw.Draw()  //  用指定接口名来解决命名冲突,记住这样不能加访问修饰符
    {
        Console.WriteLine(
" IDraw " );
    }

    
void  IDraw3D.Draw() 
    {
        Console.WriteLine(
" IDraw 3D " );
    }
}

class  Program
{
    
static   void  Main( string [] args)
    {
        Image image 
=   new  Image();

        
//  方法1
         try
        {
            ((IDraw)image).Draw();
        }
        
catch  (InvalidCastException ex)
        {
            Console.WriteLine(
" Wrong type! " );
        }

        
//  方法2
        IDraw draw  =  image  as  IDraw;
        
if  (draw  !=   null )
        {
            draw.Draw();
        }
        
else
        {
            Console.WriteLine(
" Wrong type! " );
        }

        
//  方法3
         if  (image  is  IDraw)
        {
            draw.Draw();
        }
        
else
        {
            Console.WriteLine(
" Wrong type! " );
        }
    }
}
复制代码

 

(*) 自动生成代码

实现接口的类要写不少代码,而且还经常会碰到上面说的语法问题,所以VS提供了一种自动生成代码的方式。

当写好一个类的框架后,如下:

public class Image : IDraw, IDraw3D

{}

把鼠标放在接口上,然后就不说了吧。注意有两种,一种是普通的implement,另一种是explicit implement(即带接口名且没有访问修饰符的)。

 

 

(*) 常用接口

(*) IEnumerable
实现IEnumerable接口才能使用foreach,实现IEnumerable接口只需要实现一个GetEnumerator方法。
public interface IEnumable
{
    IEnumerator GetEnumerator();
}
注意到GetEnumerator返回一个IEnumerator,这又是一个接口,定义如下:

public   interface  IEnumerator
{
    
bool  MoveNext();  //  还有下一个则前往下一个并返回ture,否则返回false
     object  Current {  get ; }  //  readonly property,这也是为什么foreach不能改写元素
     void  Reset();   //  不同于C++的迭代器,reset之后不是指向第一个元素,而是第一个元素之前
}

在实际应用中往往用不着去实现所有这些,因为很多集合例如Array已经实现好了这些接口,
比较常见的一种用法:
IEnumerable在命名空间System.Collections里。

复制代码
using  System.Collections;


class  MyItem
{
    
//
}

class  MyList : IEnumerable
{
    
private  MyItem[] myArray;

    
#region  IEnumerable Members

    
public  IEnumerator GetEnumerator()
    {
        
return  myArray.GetEnumerator();
    }

    
#endregion
}
复制代码

 

也可用yield来实现IEnumerable接口。看代码:

复制代码
public   class  DaysOfWeek : IEnumerable
{
    
string [] m_Days  =  {  " Sun " " Mon " " Tue " " Wed " " Thr " " Fri " " Sat "  };

    
#region  IEnumerable Members
    
    
public  IEnumerator GetEnumerator()
    {
        
yield   return  m_Days[ 2 ];
        
yield   return  m_Days[ 4 ];
        
yield   return  m_Days[ 6 ];
        
yield   break ;
    }

    
#endregion
}

class  TestDaysOfTheWeek
{
    
static   void  Main()
    {            
        DaysOfWeek week 
=   new  DaysOfWeek();
        
        
foreach  ( string  day  in  week)
        {
            System.Console.WriteLine(day);
        }
     
        IEnumerator myEnumerator 
=  week.GetEnumerator();
        
while  (myEnumerator.MoveNext()  ==   true )
        {
            System.Console.WriteLine(myEnumerator.Current);
        }
    }
}
复制代码

 

yield是很了不起的,它像是一个状态机,记录着迭代器中当前的位置。下面这段关于yield的话是我从别处抄来的,写的似乎很有道理:
1。代码很简洁。其实这里多了一个yield return 语句,由于yield return并不对应多余的il指令。所以编译器就会在编译的时候,生成一个实现Ienumator接口的类.并且自动维护该类的状态.比如movenext,

2. 使用yield return 很容易实现递归调用中的迭代器. 如果以上的问题,不使用yield return的话,可想而知.要么你先把所有的结果暂时放到一个对象集合中. 可是这样就以为着在迭代之前一定要计算号. 要么可能你的movenext 就相当的复杂了. .NET 编译生成的代码其实利用了state machine. 代码量也很大.

类似迭代的调用,比如二叉树遍历 用yield return 就很方便了.另外还有常说的pipeline模式也很方便了.

可是yield return 还是有一些缺陷.

比如:如果有一个参数是ref 或者 out, 那这个state machine就很难去维护状态了. 事实上,yield不支持方法带有ref或者out参数的情况. 还有很多它也不支持,例如unsafe,catch等等,详见MSDN.

 

(*) ICloneable
只要实现一个Clone方法就行了。这个有点儿像C++中自定义的拷贝构造函数,例如我们不想让多个引用同时指向一个资源,就可以在拷贝构造函数中新申请一个资源。也就是所谓的深拷贝。
需要稍微注意的一点:Clone的signature是
object Clone();
所以在调用Clone的时候经常伴随转型操作,例如:Point p2 = (Point)p1.Clone();

一个深拷贝的例子:
public object Clone()
{
 Point newPoint = (Point)this.MemberwiseClone(); // MemberwiseClone是object都有的protected方法
 // TODO: 其他需要深拷贝的操作
}

(*) IComparable
和C标准库里的binary_search的钩子函数一个道理。
public interface IComparable
{
    int CompareTo(object obj); // this在obj前面(也可以说this比obj小)返回负数,this在obj后面返回正数,相等返回0
}
实现了CompareTo方法之后,就可以用Array的静态方法Array.Sort来排序了。看下面代码:

复制代码
     class  Student : IComparable
    {
        
string  name;
        
int  score;

        
public  Student( string  name,  int  score) 
        {
            
this .name  =  name;
            
this .score  =  score;
        }

        
public   override   string  ToString()
        {
            
return  String.Format( " {0} {1} " , name, score);
        }
        
        
#region  IComparable Members

        
public   int  CompareTo( object  obj)
        {
            Student temp 
=  (Student)obj;
            
//  谁的分高谁在前
             if  ( this .score  >  temp.score) 
            {
                
return   - 1 ;
            }
            
else   if  ( this .score  <  temp.score)
            {
                
return   1 ;
            }
            
else
            {
                
return   0 ;
            }
        }

        
#endregion
    }

    
class  Program
    {
        
static   void  Main()
        {
            Student stu1 
=   new  Student( " Bill " 75 );
            Student stu2 
=   new  Student( " Steve " 85 );
            
// Console.WriteLine(stu1 > stu2);  实现了CompareTo函数也不能直接用>和<来比较
            Console.WriteLine(stu1.CompareTo(stu2));  //  若stu1比stu2靠后,则返回正数

            Student[] group 
=   new  Student[ 2 ];
            group[
0 =  stu1;
            group[
1 =  stu2;
            Array.Sort(group);
            
foreach  (Student stu  in  group)
            {
                Console.WriteLine(stu);
            }
        }
    }
复制代码

Array.Sort还提供了重载,即允许把排序准则当参数传入。

interface IComparer
{
    int Compare(object o1, object o2);
}

//实现IComparer接口的类
public class NameComparer : IComparer
{
    // 按名字排序
}

//调用
Array.Sort(group, new NameComparer);

 


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是使用C# .NET Framework写的微信扫码支付的WEB应用程序示例代码: ```csharp using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Xml; using System.Xml.Linq; using System.Security.Cryptography; using System.Text; using System.Net; using System.IO; namespace WeChatPayDemo.Controllers { public class HomeController : Controller { // 商户号 const string mch_id = "your-mch-id"; // 商户API密钥 const string api_key = "your-api-key"; // 应用ID const string appid = "your-appid"; // 通知地址 const string notify_url = "http://your-domain.com/notify"; // 支付请求地址 const string pay_url = "https://api.mch.weixin.qq.com/pay/unifiedorder"; // 首页 public ActionResult Index() { return View(); } // 支付页面 public ActionResult Pay(string total_fee) { // 生成订单号 string out_trade_no = DateTime.Now.ToString("yyyyMMddHHmmssfff") + new Random().Next(1000, 9999); // 构造支付请求参数 SortedDictionary<string, object> parameters = new SortedDictionary<string, object>(); parameters.Add("appid", appid); parameters.Add("mch_id", mch_id); parameters.Add("nonce_str", Guid.NewGuid().ToString().Replace("-", "")); parameters.Add("body", "微信扫码支付"); parameters.Add("out_trade_no", out_trade_no); parameters.Add("total_fee", int.Parse(float.Parse(total_fee) * 100 + "")); parameters.Add("spbill_create_ip", Request.UserHostAddress); parameters.Add("notify_url", notify_url); parameters.Add("trade_type", "NATIVE"); // 签名 string sign = Sign(parameters); parameters.Add("sign", sign); // 构造XML请求内容 string requestXml = BuildXml(parameters); // 发送支付请求 string responseXml = HttpPost(pay_url, requestXml); // 解析响应XML XDocument doc = XDocument.Parse(responseXml); string prepay_id = doc.Element("xml").Element("prepay_id").Value; string code_url = doc.Element("xml").Element("code_url").Value; // 构造二维码图片链接 string qr_code_url = $"https://api.qrserver.com/v1/create-qr-code/?size=150x150&data={HttpUtility.UrlEncode(code_url)}"; // 传递二维码图片链接和订单号到支付页面 ViewBag.QRCodeUrl = qr_code_url; ViewBag.OutTradeNo = out_trade_no; return View(); } // 支付结果通知接口 public ActionResult Notify() { // 接收POST数据 Stream stream = Request.InputStream; byte[] bytes = new byte[stream.Length]; stream.Read(bytes, 0, bytes.Length); string xml = Encoding.UTF8.GetString(bytes); // 解析XML数据 XDocument doc = XDocument.Parse(xml); string return_code = doc.Element("xml").Element("return_code").Value; string return_msg = doc.Element("xml").Element("return_msg").Value; string result_code = doc.Element("xml").Element("result_code").Value; string out_trade_no = doc.Element("xml").Element("out_trade_no").Value; string transaction_id = doc.Element("xml").Element("transaction_id").Value; // 验证签名 SortedDictionary<string, object> parameters = new SortedDictionary<string, object>(); parameters.Add("return_code", return_code); parameters.Add("return_msg", return_msg); parameters.Add("result_code", result_code); parameters.Add("out_trade_no", out_trade_no); parameters.Add("transaction_id", transaction_id); string sign = Sign(parameters); string sign_received = doc.Element("xml").Element("sign").Value; if (sign == sign_received) { // 处理支付结果 // ... // 返回通知结果 return Content(BuildXml(new Dictionary<string, object> { { "return_code", "SUCCESS" }, { "return_msg", "OK" } })); } else { // 签名验证失败 // ... // 返回错误信息 return Content(BuildXml(new Dictionary<string, object> { { "return_code", "FAIL" }, { "return_msg", "签名验证失败" } })); } } // 签名算法 private string Sign(IDictionary<string, object> parameters) { string stringA = string.Join("&", parameters.Where(p => !string.IsNullOrEmpty(p.Value.ToString())).OrderBy(p => p.Key).Select(p => $"{p.Key}={p.Value}")); string stringSignTemp = $"{stringA}&key={api_key}"; string sign = MD5(stringSignTemp).ToUpper(); return sign; } // MD5算法 private string MD5(string input) { MD5 md5 = MD5.Create(); byte[] buffer = Encoding.UTF8.GetBytes(input); byte[] hash = md5.ComputeHash(buffer); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hash.Length; i++) { sb.Append(hash[i].ToString("x2")); } return sb.ToString(); } // 构造XML请求内容 private string BuildXml(IDictionary<string, object> parameters) { StringBuilder sb = new StringBuilder(); sb.Append("<xml>"); foreach (var kv in parameters) { sb.Append($"<{kv.Key}>{kv.Value}</{kv.Key}>"); } sb.Append("</xml>"); return sb.ToString(); } // 发送HTTP POST请求 private string HttpPost(string url, string data) { byte[] bytes = Encoding.UTF8.GetBytes(data); HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); request.Method = "POST"; request.ContentType = "application/x-www-form-urlencoded"; request.ContentLength = bytes.Length; using (Stream stream = request.GetRequestStream()) { stream.Write(bytes, 0, bytes.Length); } using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) { using (Stream stream = response.GetResponseStream()) { using (StreamReader reader = new StreamReader(stream)) { return reader.ReadToEnd(); } } } } } } ``` 以上代码仅供参考,实际开发中需要根据实际情况进行相应的修改和完善。同时,也需要遵循相关的安全规范和隐私保护措施,确保用户信息和支付安全。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值