好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

C# 中实现ftp 图片上传功能(多快好省)

前言

此篇讲到的是 图片上传 功能,每个网站必定会有这样类似的功能,上传文件、上传图片等等。那么接下来,看看我们ef+uploadfile+ ftp 如何玩转上传图片吧

效果预览

具体实现

一个简单数据库 只有一个主键id,一个身份证正面路径和一个身份证背面路径三个字段。

首先呢,我们把实体类新建好如下:

?

public class imagemodel:baseentity

  {

   /// <summary>

   /// 用户id

   /// </summary>

   public int id { get ; set ; }

   /// <summary>

   ///身份证正面相对路径

   /// </summary>

   public string idprooffront { get ; set ; }

   /// <summary>

   ///身份证背面相对路径

   /// </summary>

   public string idproofback { get ; set ; }

  }

其中 我们将身份信息实体继承自baseentity,我们看看baseentity里面是什么东东,代码如下:

?

public abstract partial class baseentity

  {

   public override bool equals( object obj)

   {

    return equals(obj as baseentity);

   }

   private type getunproxiedtype()

   {

    return gettype();

   }

   public virtual bool equals(baseentity other)

   {

    if (other == null )

     return false ;

    if (referenceequals( this , other))

     return true ;

    return false ;

   }

   public override int gethashcode()

   {

    return base .gethashcode();

   }

   public static bool operator ==(baseentity x, baseentity y)

   {

    return equals(x, y);

   }

   public static bool operator !=(baseentity x, baseentity y)

   {

    return !(x == y);

   }

  }

这里,我们将baseentity定义成一个抽象类,里面包含一些静态方法和重载方法

======================回到html=======

我们先回过头来讲页面,上面演示的是一个很简单的单页面,html代码如下:

?

<form enctype= "multipart/form-data" id= "form" action= "/home/uploadimage" method= "post" >

  <div class = "full_w" style= "margin-top: 100px; margin-left: 30%; width: 800px;" >

   <div class = "h_title" > <b>用户上传的文件</b></div>

   <div class = "entry" >

    步骤: <span class = "red" style= "color: red" >(上传资料必须是bmp,gif,jpg,jpeg,png类型,不能大于2m)</span>

    <ol>

     <li>先按『选择』键选择上传文件;</li>

     <li>按『上传』键上传文件;</li>

     <li>按『保存』键保存文件;</li>

    </ol>

   </div>

   <div class = "entry" >

    <div class = "sep" ></div>

   </div>

   <div class = "entry" >

    <div id= "wrapper" style= "text-align: center; position: relative;" >

     <div class = "form-group" >

      <input id= "uploadfile" type= "file" value= "浏览..." class = "file" name= "filename" data-upload-url= "#" style= "position: absolute; top: 0; right: 0; min-width: 100%; min-height: 100%; text-align: right; opacity: 0; background: none repeat scroll 0 0 transparent; cursor: inherit; display: block;" />

     </div>

    </div>

   </div>

   <table>

    <tbody>

     <tr>

      <td class = "entry" >身份证正面</td>

      <td>

       @ if (model == null || model.id == null || string .isnullorempty(model.idprooffront))

       {

        <a href= "javascript:void(0);" rel= "external nofollow" rel= "external nofollow" target= "_blank" class = "winview" >

         <img style= "border: none; width: 150px; height: 100px" src= "/img/noupload.png" />

        </a>

       }

       else

       {

        <a href= "@(viewbag.pathsrc + model.idprooffront)" rel= "external nofollow" target= "_blank" class = "winview" >

         <img style= "border: none; width: 150px; height: 100px" src= "@(viewbag.pathsrc + model.idprooffront)" />

        </a>

       }

       @html.hiddenfor(m => m.idprooffront)

       @html.hiddenfor(m => m.id)

      </td>

      <td>

       <a href= "javascript:void(0)" rel= "external nofollow" rel= "external nofollow" class = "easyui-linkbutton btnfinleup" data-op= "1" data-type= "image" >上传</a>

      </td>

     </tr>

     <tr>

      <td class = "entry" >身份证背面</td>

      <span id= "lblinfosi" style= "color: green" ></span>

      <td>

       @ if (model == null || model.id == null || string .isnullorempty(model.idproofback))

       {

        <a href= "javascript:void(0);" rel= "external nofollow" rel= "external nofollow" target= "_blank" class = "winview" >

         <img style= "border: none; width: 150px; height: 100px" src= "/img/noupload.png" />

        </a>

       }

       else

       {

        <a href= "@(viewbag.pathsrc + model.idproofback)" rel= "external nofollow" target= "_blank" class = "winview" >

         <img style= "border: none; width: 150px; height: 100px" src= "@(viewbag.pathsrc + model.idproofback)" />

        </a>

       }

       @html.hiddenfor(m => m.idproofback)

      </td>

      <td>

       <a href= "javascript:void(0)" rel= "external nofollow" rel= "external nofollow" class = "easyui-linkbutton btnfinleup" data-op= "2" data-type= "image" >上传</a>

      </td>

     </tr>

    </tbody>

   </table>

   <div class = "entry" >

    <button class = "button" name= "btnsaveall" value= "保存" id= "btnsaveall" style= "height: 30px; width: 80px; text-align: center;" >保存</button>

    <a href= "/home/index" rel= "external nofollow" style= "height: 30px; text-align: center; width: 80px; background: #ffffff; border: 1px solid #dcdcdc; border-radius: 2px; color: #444444; cursor: pointer; display: inline-block; font: 700 11px tahoma, arial, sans-serif; margin-right: 10px; padding: 7px 12px 7px 12px; position: relative; text-decoration: none; text-shadow: 0px 1px 0px #ffffff;" >返回</a>

   </div>

  </div>

</form>

现在我们看页面将会毫无样式,所以我们先引用下样式,这里引用了bootstrap 和一个 style2.css ,引入样式后 界面如下:

其中,关于选择框是用了一个js单独封装起来了,是代码中的zh.js,代码如下:

?

/*!

  * fileinput chinese translations

  *

  * this file must be loaded after 'fileinput.js'. patterns in braces '{}', or

  * any html markup tags in the messages must not be converted or translated.

  *

  * @see http://github测试数据/kartik-v/bootstrap-fileinput

  * @author kangqf <kangqingfei@gmail测试数据>

  *

  * note: this file must be saved in utf-8 encoding.

  */

(function ($) {

  "use strict" ;

  $.fn.fileinputlocales[ 'zh' ] = {

   filesingle: '文件' ,

   fileplural: '个文件' ,

   browselabel: '选择 …' ,

   removelabel: '移除' ,

   removetitle: '清除选中文件' ,

   cancellabel: '取消' ,

   canceltitle: '取消进行中的上传' ,

   uploadlabel: '上传' ,

   uploadtitle: '上传选中文件' ,

   msgno: '没有' ,

   msgnofilesselected: '' ,

   msgcancelled: '取消' ,

   msgzoommodalheading: '详细预览' ,

   msgsizetoosmall: 'file "{name}" (<b>{size} kb</b>) is too small and must be larger than <b>{minsize} kb</b>.' ,

   msgsizetoolarge: '文件 "{name}" (<b>{size} kb</b>) 超过了允许大小 <b>{maxsize} kb</b>.' ,

   msgfilestooless: '你必须选择最少 <b>{n}</b> {files} 来上传. ' ,

   msgfilestoomany: '选择的上传文件个数 <b>({n})</b> 超出最大文件的限制个数 <b>{m}</b>.' ,

   msgfilenotfound: '文件 "{name}" 未找到!' ,

   msgfilesecured: '安全限制,为了防止读取文件 "{name}".' ,

   msgfilenotreadable: '文件 "{name}" 不可读.' ,

   msgfilepreviewaborted: '取消 "{name}" 的预览.' ,

   msgfilepreviewerror: '读取 "{name}" 时出现了一个错误.' ,

   msginvalidfilename: 'invalid or unsupported characters in file name "{name}".' ,

   msginvalidfiletype: '不正确的类型 "{name}". 只支持 "{types}" 类型的文件.' ,

   msginvalidfileextension: '不正确的文件扩展名 "{name}". 只支持 "{extensions}" 的文件扩展名.' ,

   msgfiletypes: {

    'image' : 'image' ,

    'html' : 'html' ,

    'text' : 'text' ,

    'video' : 'video' ,

    'audio' : 'audio' ,

    'flash' : 'flash' ,

    'pdf' : 'pdf' ,

    'object' : 'object'

   },

   msguploadaborted: '该文件上传被中止' ,

   msguploadthreshold: 'processing...' ,

   msguploadempty: 'no valid data available for upload.' ,

   msgvalidationerror: '验证错误' ,

   msgloading: '加载第 {index} 文件 共 {files} …' ,

   msgprogress: '加载第 {index} 文件 共 {files} - {name} - {percent}% 完成.' ,

   msgselected: '{n} {files} 选中' ,

   msgfoldersnotallowed: '只支持拖拽文件! 跳过 {n} 拖拽的文件夹.' ,

   msgimagewidthsmall: '宽度的图像文件的"{name}"的必须是至少{size}像素.' ,

   msgimageheightsmall: '图像文件的"{name}"的高度必须至少为{size}像素.' ,

   msgimagewidthlarge: '宽度的图像文件"{name}"不能超过{size}像素.' ,

   msgimageheightlarge: '图像文件"{name}"的高度不能超过{size}像素.' ,

   msgimageresizeerror: '无法获取的图像尺寸调整。' ,

   msgimageresizeexception: '错误而调整图像大小。<pre>{errors}</pre>' ,

   msgajaxerror: 'something went wrong with the {operation} operation. please try again later!' ,

   msgajaxprogresserror: '{operation} failed' ,

   ajaxoperations: {

    deletethumb: 'file delete' ,

    uploadthumb: 'single file upload' ,

    uploadbatch: 'batch file upload' ,

    uploadextra: 'form data upload'

   },

   dropzonetitle: '拖拽文件到这里 …<br>支持多文件同时上传' ,

   dropzoneclicktitle: '<br>(或点击{files}按钮选择文件)' ,

   fileactionsettings: {

    removetitle: '删除文件' ,

    uploadtitle: '上传文件' ,

    zoomtitle: '查看详情' ,

    dragtitle: '移动 / 重置' ,

    indicatornewtitle: '没有上传' ,

    indicatorsuccesstitle: '上传' ,

    indicatorerrortitle: '上传错误' ,

    indicatorloadingtitle: '上传 ...'

   },

   previewzoombuttontitles: {

    prev: '预览上一个文件' ,

    next: '预览下一个文件' ,

    toggleheader: '缩放' ,

    fullscreen: '全屏' ,

    borderless: '无边界模式' ,

    close: '关闭当前预览'

   }

  };

})(window.jquery);

好了,界面大概就整成这样子,现在需要我们实现功能了。首先用js将上传控件初始化一下:

?

//上传控件初始化

  function initfileupload() {

   $( "#uploadfile" ).fileinput({

    //uploadextradata: { kvid: '10' },

    language: 'zh' , //设置语言

    showupload: false , //是否显示上传按钮

    uploadasync: true , //默认异步上传

    showremove: false ,

    autoreplace: true ,

    maxfilecount: 1,

    maxfilesize: 10240,

    dropzonetitle: '拖拽文件到这里 …<br>仅限.pdf, .jpg, .jpeg, .gif' ,

    enctype: 'multipart/form-data' ,

    fileactionsettings: { uploadclass: "hidden" , zoomclass: "hidden" , removeclass: "hidden" },

    allowedfileextensions: [ 'jpg' , 'png' , 'gif' , 'pdf' ], //接收的文件后缀

    msgfilestoomany: "选择上传的文件数量({n}) 超过允许的最大数值{m}!" ,

    uploadurl: "/fileupload/fileupload" , //上传的地址

   }).on( "filebatchselected" , function ( event , files) {

    $( ".file-preview-success" ).remove();

   })

   $( "#uploadfile" ).on( "fileuploaded" , function ( event , data, previewid, index) {

    console.log( "accountdata 初始化后 fileopt" + accountdata);

    console.log( "accountdata.fileopt " + accountdata.fileopt);

    var obj = data.response;

    if (obj.status != 500 && obj.data != undefined) {

     var src = accountdata.pathsrc + obj.data.filename;

     showname = obj.data.filename;

     //alert(showname);

     var pid = accountdata.pid;

     var fileobj = undefined;

     var field = "" ;

     var ispdf = false ;

     debugger;

     if (accountdata.fileopt == 1) {

      fileobj = $( "#idprooffront" );

      //$("#personinfo_oldidfile").val(obj.data.filename);

      field = "idprooffront" ;

      fileobj.val(obj.data.filename);

     } else if (accountdata.fileopt == 2) {

      fileobj = $( "#idproofback" );

      field = "idproofback" ;

      $( "#idproofback" ).val(showname);

      fileobj.val(obj.data.filename);

     }

     //fileobj = $("#idprooffront");

     //$("#idprooffront").val(obj.data.filename);

     //field = "idprooffront";

     //fileobj.val(obj.data.filename);

     fileobj.prev().attr( "href" , src);

     src = ispdf == true ? "/content/images/pdf.png" : src;

     fileobj.prev().find( "img" ).attr( "src" , src);

    } else {

     console.error(obj.data);

    }

   });

   $( '#uploadfile' ).on( 'filesuccessremove' , function ( event , id) {

   });

   $( '#uploadfile' ).on( 'fileerror' , function ( event , data, msg) {

   });

   //上传

   $( ".btnfinleup" ).click(function () {

    var filename = $( "#uploadfile" ).val();

    var obj = document.getelementbyid( "uploadfile" );

    var type = $( this ).attr( "data-op" );

    //alert("当前点击的type是:" + type);

    var filetype = $( this ).attr( "data-type" );

    var files = $( "#uploadfile" ).fileinput( "getfilestack" );

    if (files.length == 0) {

     layer.msg( '请选择要上传的文件' , function () { });

     return ;

    }

    var array = filetype.split( "," );

    var selecttype = files[0].type.tolowercase();

    var falg = false ;

    for (var i = 0; i < array.length; i++) {

     if (selecttype.indexof(array[i]) == -1) {

      falg = false ;

     } else

      falg = true ;

     if (falg)

      break ;

    }

    if (!falg) {

     layer.msg( '只能选择' + filetype + ' 类型的文件' , function () { });

     return ;

    }

    accountdata.fileopt = type;

    $( "#uploadfile" ).fileinput( "upload" );

   });

  }

然后再 加载页面的时候调用这个初始化即可

?

$(function () {

   initfileupload();

})

ftp上传操作

注意,再initfileupload方法中 上传了图片,会自动访问uploadurl 这个url地址,存放图片,我们先看看这个action如何通过ftp上传指定服务器的。

fileupload方法如下

?

/// <summary>

   /// 通过ftp上传指定服务器

   /// </summary>

   /// <returns></returns>

   public actionresult fileupload()

   {

    bool flag = false ;

    string msg = string .empty;

    int size = convert.toint16(_filesize) * 1024 * 1024;

    try

    {

     dictionary< string , string > filedict = new dictionary< string , string >();

     for ( int i = 0; i < request.files.count; i++)

     {

      httppostedfilebase file = request.files[i];

      string extension = path.getextension(file.filename);

      string [] fileextensions = _fileextension.split( ';' );

      if (fileextensions.any(o => o.equals(extension, stringcomparison.ordinalignorecase)))

      {

       if (file.contentlength <= size)

       {

        string filename = string .format( "{0}_{1}" , datetime.now.tostring( "yyyymmddhhmmssfff" ), path.getfilename(file.filename));

        if (file.contentlength <= 10 * 1024 * 1024)

        {

         byte [] buffer = new byte [file.contentlength];

         file.inputstream.read(buffer, 0, file.contentlength);

         flag = fileupload(buffer, file.filename, out filename, out msg);

        }

        else //图片压缩有问题>>

        {

         var stream = imagehelper.getpicthumbnail(file.inputstream, 40);

         byte [] buffer = new byte [stream.length];

         stream.read(buffer, 0, ( int )stream.length);

         flag = fileupload(buffer, file.filename, out filename, out msg);

        }

        filedict.add(request.files.allkeys[i], filename);

       }

       else

       {

        msg = string .format( "上传文件不能大于{0}m" , _filesize);

       }

      }

      else

      {

       msg = string .format( "上传的文件类型不正确" );

      }

     }

     return json( new { result = "0" , msg = "" + msg, data = filedict });

    }

    catch (exception ex)

    {

     return json( new { result = "0" , msg = "网络异常,请稍后再试" });

    }

   }

其中 _fileextension _filepath _filesize 是分别从配置文件中读取出来的如下:     

?

private static string _fileextension = configurationmanager.appsettings[ "filetype" ];

   private readonly string _filepath = configurationmanager.appsettings[ "uploadpath" ];

   private readonly string _filesize = configurationmanager.appsettings[ "filesizem" ];

方法中有一个 fileupload 上传文件的方法 如下:

?

/// <summary>

   /// 上传文件

   /// </summary>

   /// <param name="filebytes"></param>

   /// <param name="originalname"></param>

   /// <param name="msg"></param>

   /// <returns></returns>

   protected bool fileupload( byte [] filebytes, string originalname, out string newfilename, out string msg)

   {

    msg = "" ;

    newfilename = "" ;

    try

    {

     ftpupfile ftp = new ftpupfile();

     newfilename = ftp.upfile(filebytes, originalname);

     if ( string .isnullorempty(newfilename))

     {

      msg = "上传文件时出错!" ;

      return false ;

     }

     return true ;

    }

    catch (exception ex)

    {

     msg = ex.message;

     return false ;

    }

   }

其中

ftpupfile 是一个ftp上传文件帮助类,大家可以直接照搬 ,代码如下:

?

/// <summary>

  /// ftp上传文件

  /// </summary>

  public class ftpupfile

  {

   string filetype = configurationmanager.appsettings[ "filetype" ];

   string ipaddress = configurationmanager.appsettings[ "ipaddress" ];

   string username = configurationmanager.appsettings[ "username" ];

   string password = configurationmanager.appsettings[ "password" ];

   /// <summary>

   /// ftp上传文件

   /// </summary>

   /// <param name="filename">上传文件路径</param>

   /// <param name="ftpserverip">ftp服务器的ip和端口</param>

   /// <param name="ftppath">ftp服务器下的哪个目录</param>

   /// <param name="ftpuserid">ftp用户名</param>

   /// <param name="ftppassword">ftp密码</param>

   public bool upload( string filename, string ftpserverip, string ftppath, string ftpuserid, string ftppassword)

   {

    fileinfo fileinf = new fileinfo(filename);

    string uri = "ftp://" + ftpserverip + "/" + ftppath + "/" + fileinf.name;

    try

    {

     ftpwebrequest reqftp = (ftpwebrequest)ftpwebrequest.create( new uri(uri));

     // ftp用户名和密码

     reqftp.credentials = new networkcredential(ftpuserid, ftppassword);

     reqftp.keepalive = false ;

     // 指定执行什么命令

     reqftp.method = webrequestmethods.ftp.uploadfile;

     // 指定数据传输类型

     reqftp.usebinary = true ;

     // 上传文件时通知服务器文件的大小

     reqftp.contentlength = fileinf.length;

     //this.invoke(inituprogress, fileinf.length);

     // 缓冲大小设置为2kb

     int bufflength = 4096;

     byte [] buff = new byte [bufflength];

     int contentlen;

     // 打开一个文件流 (system.io.filestream) 去读上传的文件

     filestream fs = fileinf.openread();

     // 把上传的文件写入流

     stream strm = reqftp.getrequeststream();

     contentlen = fs.read(buff, 0, bufflength);

     while (contentlen != 0)

     {

      strm.write(buff, 0, contentlen);

      contentlen = fs.read(buff, 0, bufflength);

     }

     // 关闭两个流

     strm.close();

     strm.dispose();

     fs.close();

     fs.dispose();

     return true ;

    }

    catch (exception ex)

    {

     return false ;

    }

   }

   /// <summary>

   /// 新建目录

   /// </summary>

   /// <param name="ftppath"></param>

   /// <param name="dirname"></param>

   public void makedir( string ftppath, string dirname, string username, string password)

   {

    try

    {

     //实例化ftp连接

     ftpwebrequest request = (ftpwebrequest)ftpwebrequest.create( new uri(ftppath + dirname));

     // ftp用户名和密码

     request.credentials = new networkcredential(username, password);

     // 默认为true,连接不会被关闭

     request.keepalive = false ;

     //指定ftp操作类型为创建目录

     request.method = webrequestmethods.ftp.makedirectory;

     //获取ftp服务器的响应

     ftpwebresponse response = (ftpwebresponse)request.getresponse();

     response.close();

    }

    catch (exception ex)

    {

     //respons

    }

   }

   /// <summary>

   /// 删除指定文件

   /// </summary>

   /// <param name="ftppath"></param>

   /// <param name="dirname"></param>

   /// <param name="username"></param>

   /// <param name="password"></param>

   public void deletefile( string ftppath, string username, string password)

   {

    try

    {

     // string uri = "ftp://" + ftpserverip + "/" + ftppath + "/" + fileinf.name;

     //ftppath = "ftp://192.168.1.111:2005/2012-12-05/20121206o5catice.docx";

     //password = "111";

     //username = "yuanluluoli";

     //实例化ftp连接

     ftpwebrequest request = (ftpwebrequest)ftpwebrequest.create( new uri(ftppath));

     request.method = webrequestmethods.ftp.deletefile;

     // ftp用户名和密码

     request.credentials = new networkcredential(username, password);

     // 默认为true,连接不会被关闭

     request.keepalive = false ;

     //获取ftp服务器的响应

     ftpwebresponse response = (ftpwebresponse)request.getresponse();

     response.close();

    }

    catch (exception ex)

    {

     //respons

    }

   }

   /// <summary>

   /// 检查目录是否存在

   /// </summary>

   /// <param name="ftppath">要检查的目录的路径</param>

   /// <param name="dirname">要检查的目录名</param>

   /// <returns>存在返回true,否则false</returns>

   public bool checkdirectoryexist( string ftppath, string dirname, string username, string password)

   {

    bool result = false ;

    try

    {

     //实例化ftp连接

     ftpwebrequest request = (ftpwebrequest)ftpwebrequest.create( new uri(ftppath));

     // ftp用户名和密码

     request.credentials = new networkcredential(username, password);

     request.keepalive = false ;

     //指定ftp操作类型为创建目录

     request.method = webrequestmethods.ftp.listdirectorydetails;

     //获取ftp服务器的响应

     ftpwebresponse response = (ftpwebresponse)request.getresponse();

     streamreader sr = new streamreader(response.getresponsestream(), encoding. default );

     stringbuilder str = new stringbuilder();

     string line = sr.readline();

     while (line != null )

     {

      str.append(line);

      str.append( "|" );

      line = sr.readline();

     }

     string [] datas = str.tostring().split( '|' );

     for ( int i = 0; i < datas.length; i++)

     {

      if (datas[i].contains( "<dir>" ))

      {

       int index = datas[i].indexof( "<dir>" );

       string name = datas[i].substring(index + 5).trim();

       if (name == dirname)

       {

        result = true ;

        break ;

       }

      }

     }

     sr.close();

     sr.dispose();

     response.close();

    }

    catch (exception)

    {

     return false ;

    }

    return result;

   }

   /// <summary>

   /// 上传文件

   /// </summary>

   /// <param name="buffer">文件的byte数组</param>

   /// <param name="originalname">文件原始名字(带后缀名)</param>

   /// <param name="perstr">新文件名的前缀</param>

   /// <returns></returns>

   public string upfile( byte [] buffer, string originalname, string perstr = "" )

   {

    if (buffer == null || buffer.length <= 0 || string .isnullorempty(originalname))

     throw new argumentexception( "参数错误!" );

    string filepathstr = string .empty;

    string filepathsql = null ;

    try

    {

     string pathstr = perstr + datetime.now.tostring().replace( "/" , "" ).replace( "-" , "" ).replace( ":" , "" ).replace( " " , "" );

     string rodumlist = generalhelper.getmixpwd(10); //10位随机数

     filepathstr = "~/file/" + pathstr + rodumlist + path.getextension(originalname);

     //stream sr = upfile.postedfile.inputstream;

     //byte[] file = new byte[sr.length];

     //sr.read(file, 0, file.length);

     streamwriter sw = new streamwriter(httpcontext.current.server.mappath(filepathstr));

     sw.basestream.write(buffer, 0, buffer.length);

     sw.flush(); sw.close();

     // file.saveas(httpcontext.current.server.mappath(filepathstr));//把文件上传到服务器的绝对路径上

     bool check;

     string ftppath = datetime.now.tostring( "yyyy-mm-dd" );

     string uri = @"ftp://" + ipaddress + "/" ;

     //检查是否存在此目录文件夹

     if (checkdirectoryexist(uri, ftppath, username, password))

     {

      //存在此文件夹就直接上传

      check = upload(httpcontext.current.server.mappath(filepathstr), ipaddress, ftppath, username, password);

     }

     else

     {

      makedir(uri, ftppath, username, password); //创建

      check = upload(httpcontext.current.server.mappath(filepathstr), ipaddress, ftppath, username, password);

     }

     //成功就更新

     if (check)

     {

      filepathsql = ftppath + "/" + pathstr + rodumlist + path.getextension(originalname);

     }

     //检查是否存在此文件

     if (file.exists(httpcontext.current.server.mappath(filepathstr)))

     {

      file.delete(httpcontext.current.server.mappath(filepathstr));

     }

     return filepathsql;

    }

    catch (exception ex)

    {

     file.delete(httpcontext.current.server.mappath(filepathstr));

     throw ex;

    }

   }

   /// <summary>

   /// 上传文件

   /// 不修改名字及后缀名

   /// </summary>

   /// <param name="originalfilepath">上传文件的绝对路径</param>

   /// <returns></returns>

   public string upfile( string originalfilepath)

   {

    if ( string .isnullorempty(originalfilepath))

     throw new argumentexception( "参数错误!" );

    string filepathsql = null ;

    try

    {

     //检查是否存在此文件

     if (!file.exists(originalfilepath))

      throw new exception( "文件不存在!" );

     //stream sr = upfile.postedfile.inputstream;

     //byte[] file = new byte[sr.length];

     //sr.read(file, 0, file.length);

     // file.saveas(httpcontext.current.server.mappath(filepathstr));//把文件上传到服务器的绝对路径上

     bool check;

     string ftppath = datetime.now.tostring( "yyyy-mm-dd" );

     string uri = @"ftp://" + ipaddress + "/" ;

     //检查是否存在此目录文件夹

     if (checkdirectoryexist(uri, ftppath, username, password))

     {

      //存在此文件夹就直接上传

      check = upload(originalfilepath, ipaddress, ftppath, username, password);

     }

     else

     {

      makedir(uri, ftppath, username, password); //创建

      check = upload(originalfilepath, ipaddress, ftppath, username, password);

     }

     //成功就更新

     if (check)

     {

      filepathsql = ftppath + "/" + path.getfilename(originalfilepath);

     }

     //检查是否存在此文件

     if (file.exists(originalfilepath))

     {

      file.delete(originalfilepath);

     }

     return filepathsql;

    }

    catch (exception ex)

    {

     //file.delete(originalfilepath);

     throw ex;

    }

   }

   public string ftp_up(htmlinputfile upfile)

   {

    //encrypt en = new encrypt();

    string filepathstr = string .empty;

    string filepathsql = null ;

    try

    {

     string pathstr = datetime.now.tostring().replace( "/" , "" ).replace( "-" , "" ).replace( ":" , "" ).replace( " " , "" );

     string rodumlist = generalhelper.getmixpwd(10); //10位随机数

     filepathstr = "~/file/" + pathstr + rodumlist + path.getextension(upfile.postedfile.filename);

     stream sr = upfile.postedfile.inputstream;

     byte [] file = new byte [sr.length];

     sr.read(file, 0, file.length);

     streamwriter sw = new streamwriter(httpcontext.current.server.mappath(filepathstr));

     sw.basestream.write(file, 0, file.length);

     sw.flush(); sw.close(); sr.flush(); sr.close();

     // file.saveas(httpcontext.current.server.mappath(filepathstr));//把文件上传到服务器的绝对路径上

     bool check;

     string ftppath = datetime.now.tostring( "yyyy-mm-dd" );

     string uri = @"ftp://" + ipaddress + "/" ;

     //检查是否存在此目录文件夹

     if (checkdirectoryexist(uri, ftppath, username, password))

     {

      //存在此文件夹就直接上传

      check = upload(httpcontext.current.server.mappath(filepathstr), ipaddress, ftppath, username, password);

     }

     else

     {

      makedir(uri, ftppath, username, password); //创建

      check = upload(httpcontext.current.server.mappath(filepathstr), ipaddress, ftppath, username, password);

     }

     //成功就更新

     if (check)

     {

      filepathsql = ftppath + "/" + pathstr + rodumlist + path.getextension(upfile.postedfile.filename);

     }

     //检查是否存在此文件

     if (file.exists(httpcontext.current.server.mappath(filepathstr)))

     {

      file.delete(httpcontext.current.server.mappath(filepathstr));

     }

     return filepathsql;

    }

    catch (exception)

    {

     file.delete(httpcontext.current.server.mappath(filepathstr));

     return filepathsql;

     // response.write("<script>alert(" + ex.message + ");</script>");

    }

   }

   /// <summary>

   /// 上传

   /// </summary>

   /// <param name="file"></param>

   /// <returns></returns>

   public string ftp_up(httppostedfilebase postedfile)

   {

    string filepathstr = string .empty;

    string filepathsql = null ;

    try

    {

     string pathstr = datetime.now.tostring( "yyyymmddhhmmss" );

     string rodumlist = generalhelper.getmixpwd(10); //10位随机数

     string filename = system.io.path.getfilename(postedfile.filename);

     string eextension = path.getextension(filename);

     string strlocation = httpcontext.current.server.mappath( "~/file/" );

     filepathstr = strlocation + pathstr + rodumlist + eextension;

     postedfile.saveas(filepathstr);

     bool check;

     string ftppath = datetime.now.tostring( "yyyy-mm-dd" );

     string uri = @"ftp://" + ipaddress + "/" ;

     //检查是否存在此目录文件夹

     if (checkdirectoryexist(uri, ftppath, username, password))

     {

      //存在此文件夹就直接上传

      check = upload(filepathstr, ipaddress, ftppath, username, password);

     }

     else

     {

      makedir(uri, ftppath, username, password); //创建

      check = upload(filepathstr, ipaddress, ftppath, username, password);

     }

     //成功就更新

     if (check)

     {

      filepathsql = ftppath + "/" + pathstr + rodumlist + eextension;

     }

     //检查是否存在此文件

     if (file.exists(filepathstr))

     {

      file.delete(filepathstr);

     }

     return filepathsql;

    }

    catch (exception ex)

    {

     //检查是否存在此文件

     if (file.exists(filepathstr))

     {

      file.delete(filepathstr);

     }

     return "" ;

     // response.write("<script>alert(" + ex.message + ");</script>");

    }

   }

   /// <summary>

   /// ftp下载文件在服务器目录

   /// </summary>

   /// <param name="pathname">本地保存目录路径和文件名称</param>

   /// <param name="filename">ftp目录路径和文件名称</param>

   /// <returns></returns>

   public bool filedown( string pathname, string filename)

   {

    string uri = "ftp://" + ipaddress + "/" + filename;

    string filename = pathname; //本地保存目录

    //创建一个文件流

    filestream fs = null ;

    stream responsestream = null ;

    try

    {

     //创建一个与ftp服务器联系的ftpwebrequest对象

     ftpwebrequest request = (ftpwebrequest)webrequest.create( new uri(uri));

     //连接登录ftp服务器

     request.credentials = new networkcredential(username, password);

     request.keepalive = false ;

     //设置请求的方法是ftp文件下载

     request.method = webrequestmethods.ftp.downloadfile;

     //获取一个请求响应对象

     ftpwebresponse response = (ftpwebresponse)request.getresponse();

     //获取请求的响应流

     responsestream = response.getresponsestream();

     //判断本地文件是否存在,如果存在,则打开和重写本地文件

     if (file.exists(filename))

      fs = file.open(filename, filemode.open, fileaccess.readwrite);

     //判断本地文件是否存在,如果不存在,则创建本地文件

     else

     {

      fs = file.create(filename);

     }

     if (fs != null )

     {

      int buffer_count = 65536;

      byte [] buffer = new byte [buffer_count];

      int size = 0;

      while ((size = responsestream.read(buffer, 0, buffer_count)) > 0)

      {

       fs.write(buffer, 0, size);

      }

      fs.flush();

      fs.close();

      responsestream.close();

     }

     return true ;

    }

    catch (exception ex)

    {

     return false ;

    }

    finally

    {

     if (fs != null )

      fs.close();

     if (responsestream != null )

      responsestream.close();

    }

   }

   /// <summary>

   /// 保存和上传图片

   /// </summary>

   /// <param name="imgtwo">需要上传图片</param>

   /// <param name="date"></param>

   /// <returns>文件路径</returns>

   public string saveuploadimg(bitmap imgtwo)

   {

    string filepathstr = string .empty;

    string filepathsql = null ;

    try

    {

     string pathstr = datetime.now.tostring().replace( "/" , "" ).replace( "-" , "" ).replace( ":" , "" ).replace( " " , "" );

     string rodumlist = generalhelper.getmixpwd(10); //10位随机数

     filepathstr = "~/file/" + pathstr + rodumlist + ".jpg" ;

     imgtwo.save(httpcontext.current.server.mappath(filepathstr)); //把文件上传到服务器的绝对路径上

     bool check;

     string ftppath = datetime.now.tostring( "yyyy-mm-dd" );

     string uri = @"ftp://" + ipaddress + "/" ;

     //检查是否存在此目录文件夹

     if (checkdirectoryexist(uri, ftppath, username, password))

     {

      //存在此文件夹就直接上传

      check = upload(httpcontext.current.server.mappath(filepathstr), ipaddress, ftppath, username, password);

     }

     else

     {

      makedir(uri, ftppath, username, password); //创建

      check = upload(httpcontext.current.server.mappath(filepathstr), ipaddress, ftppath, username, password);

     }

     //成功就更新

     if (check)

     {

      filepathsql = ftppath + "/" + pathstr + rodumlist + ".jpg" ;

     }

     //检查是否存在此文件

     if (file.exists(httpcontext.current.server.mappath(filepathstr)))

     {

      file.delete(httpcontext.current.server.mappath(filepathstr));

     }

     imgtwo.dispose();

     return filepathsql;

    }

    catch (exception ex)

    {

     file.delete(httpcontext.current.server.mappath(filepathstr));

     return filepathsql;

    }

   }

   #region

   /// <summary>

   /// 文件大小

   /// </summary>

   public bool _file_length( int contentlength)

   {

    bool length = false ;

    int filelen = contentlength;

    if (filelen > 2048 * 1024 == false ) //不能超过2m

    {

     length = true ;

    }

    return length;

   }

   #endregion

   //用来获取文件类型

   public bool file_pastfilename( string filename)

   {

    //bmp, doc, docx, gif, jpg, jpeg, pdf, png, tif, tiff

    bool isnot = true ;

    string ext = path.getextension(filename);

    string [] type = filetype.split( ';' );

    for ( int i = 0; i < type.length; i++)

    {

     if (type[i].tolower() == ext.tolower())

     {

      isnot = false ;

      break ;

     }

    }

    return isnot;

   }

  }

值得注意的是:帮助类中也从配置文件中读取了存放地址、文件类型、用户名、密码等必要信息。这个大家可以自己再配置文件中配置,配置好了如下所示:

?

<add key= "filesizem" value= "10" ></add>

<add key= "filetype" value= ".bmp;.gif;.jpg;.jpeg;.png;.pdf" />

<!---本地测试-->

<add key= "ipaddress" value= "路径" />

<!--ftp上传文件的帐号-->

<add key= "username" value= "账号" />

<!--ftp上传文件的密码-->

<add key= "password" value= "密码" />

<!--后台显示图片地址-->

<add key= "pathsrc" value= "路径" />

还有一个类是图片帮助类,代码如下:

?

public class imagehelper

  {

   /// <summary>

   /// 图片压缩

   /// </summary>

   /// <param name="sfile">原图路径</param>

   /// <param name="dfile">保存路径</param>

   /// <param name="flag">压缩质量(数字越小压缩率越高) 1-100</param>

   /// <param name="dwidth">宽度</param>

   /// <param name="dheight">高度</param>

   /// <returns></returns>

   public static bool savepicthumbnail( string sfile, string dfile, int flag, int dwidth = 0, int dheight = 0)

   {

 

    system.drawing.image isource = system.drawing.image.fromfile(sfile);

    return savepicthumbnail(dfile, flag, isource, dwidth, dheight);

 

 

   }

   /// <summary>

   /// 图片压缩

   /// </summary>

   /// <param name="sfile">原图流</param>

   /// <param name="dfile">保存路径</param>

   /// <param name="flag">压缩质量(数字越小压缩率越高) 1-100</param>

   /// <param name="dwidth">宽度</param>

   /// <param name="dheight">高度</param>

   /// <returns></returns>

   public static bool savepicthumbnail(stream stream, string dfile, int flag, int dwidth = 0, int dheight = 0)

   {

 

    system.drawing.image isource = system.drawing.image.fromstream(stream);

    return savepicthumbnail(dfile, flag, isource, dwidth, dheight);

 

   }

 

 

 

   #region getpicthumbnail

 

   public static stream getpicthumbnail(stream stream , int flag, int dwidth = 0, int dheight = 0)

   {

    system.drawing.image isource = system.drawing.image.fromstream(stream);

    imageformat tformat = isource.rawformat;

    int sw = 0, sh = 0;

    if (dheight == 0 && dwidth == 0)

    {

     sw = isource.width;

     sh = isource.height;

    }

    else if (dwidth != 0)

    {

     sw = dwidth;

     sh = isource.height * dwidth / isource.width;

    }

    else if (dheight != 0)

    {

     sh = dheight;

     sw = isource.width * dheight / isource.height;

    }

    bitmap ob = new bitmap(sw, sh);

    graphics g = graphics.fromimage(ob);

    g.clear(color.whitesmoke);

    g测试数据positingquality = compositingquality.highquality;

    g.smoothingmode = smoothingmode.highquality;

    g.interpolationmode = interpolationmode.highqualitybicubic;

    g.drawimage(isource, new rectangle(0, 0, sw, sh), 0, 0, isource.width, isource.height, graphicsunit.pixel);

    g.dispose();

    //以下代码为保存图片时,设置压缩质量

    encoderparameters ep = new encoderparameters();

    long [] qy = new long [1];

    qy[0] = flag; //设置压缩的比例1-100

    encoderparameter eparam = new encoderparameter(system.drawing.imaging.encoder.quality, qy);

    ep.param[0] = eparam;

    memorystream ms = new memorystream();

    try

    {

     imagecodecinfo[] arrayici = imagecodecinfo.getimageencoders();

     imagecodecinfo jpegiciinfo = null ;

     for ( int x = 0; x < arrayici.length; x++)

     {

      if (arrayici[x].formatdescription.equals( "jpeg" ))

      {

       jpegiciinfo = arrayici[x];

       break ;

      }

     }

     if (jpegiciinfo != null )

     {

      ob.save(ms, jpegiciinfo, ep); //dfile是压缩后的新路径

 

     }

     else

     {

      ob.save(ms, tformat);

     }

    

     return stream;

    }

    catch

    {

     return null ;

    }

    finally

    {

     isource.dispose();

     ob.dispose();

    }

   }

 

 

   public static bool savepicthumbnail( string dfile, int flag, system.drawing.image isource, int dwidth = 0, int dheight = 0)

   {

 

    imageformat tformat = isource.rawformat;

    int sw = 0, sh = 0;

    if (dheight == 0 && dwidth == 0)

    {

     sw = isource.width;

     sh = isource.height;

    }

    else if (dwidth != 0)

    {

     sw = dwidth;

     sh = isource.height * dwidth / isource.width;

    }

    else if (dheight != 0)

    {

     sh = dheight;

     sw = isource.width * dheight / isource.height;

    }

    bitmap ob = new bitmap(sw, sh);

    graphics g = graphics.fromimage(ob);

    g.clear(color.whitesmoke);

    g测试数据positingquality = compositingquality.highquality;

    g.smoothingmode = smoothingmode.highquality;

    g.interpolationmode = interpolationmode.highqualitybicubic;

    g.drawimage(isource, new rectangle(0, 0, sw, sh), 0, 0, isource.width, isource.height, graphicsunit.pixel);

    g.dispose();

    //以下代码为保存图片时,设置压缩质量

    encoderparameters ep = new encoderparameters();

    long [] qy = new long [1];

    qy[0] = flag; //设置压缩的比例1-100

    encoderparameter eparam = new encoderparameter(system.drawing.imaging.encoder.quality, qy);

    ep.param[0] = eparam;

    try

    {

     imagecodecinfo[] arrayici = imagecodecinfo.getimageencoders();

     imagecodecinfo jpegiciinfo = null ;

     for ( int x = 0; x < arrayici.length; x++)

     {

      if (arrayici[x].formatdescription.equals( "jpeg" ))

      {

       jpegiciinfo = arrayici[x];

       break ;

      }

     }

     if (jpegiciinfo != null )

     {

      ob.save(dfile, jpegiciinfo, ep); //dfile是压缩后的新路径

     }

     else

     {

      ob.save(dfile, tformat);

     }

     return true ;

    }

    catch

    {

     return false ;

    }

    finally

    {

     isource.dispose();

     ob.dispose();

    }

   }

   #endregion

  }

然后我们通过在fileuploaded的回调函数中绑定url即可显示上传后的图片,效果如下图:

不过这个只是上传到ftp服务器上了,并没有保存到数据库,现在我们要做的就是通过ef的方式将上传的图片保存到数据库。

保存图片

首先我们要建一个操作的接口基类,并且还要约束成baseentity,代码如下

?

public interface irepository<t> where t : baseentity

  {

   /// <summary>

   /// 根据过滤条件,获取记录

   /// </summary>

   /// <param name="exp"></param>

   /// <param name="isnotracking">(默认不跟踪实体状态)使用notracking的查询会在性能方面得到改善</param>

   /// <returns></returns>

   iqueryable<t> find(expression<func<t, bool >> exp = null , bool isnotracking = true );

   /// <summary>

   /// 根据过滤条件,获取记录

   /// </summary>

   /// <param name="wherelambda"></param>

   /// <param name="isnotracking">(默认不跟踪实体状态)使用notracking的查询会在性能方面得到改善</param>

   /// <param name="values"></param>

   /// <returns></returns>

   iqueryable<t> find( string wherelambda = null , bool isnotracking = true , params object [] values);

   iqueryable<tentity> othertable<tentity>() where tentity : baseentity;

   idbset<tentity> set <tentity>() where tentity : baseentity;

   /// <summary>

   /// 判断记录是否存在

   /// </summary>

   /// <param name="exp"></param>

   /// <returns></returns>

   bool isexist(expression<func<t, bool >> exp);

   /// <summary>

   /// 查找单个(如果没找到则返回为null)

   /// </summary>

   /// <param name="exp"></param>

   /// <param name="isnotracking">(默认不跟踪实体状态)使用notracking的查询会在性能方面得到改善</param>

   /// <returns></returns>

   t findsingle(expression<func<t, bool >> exp, bool isnotracking = true );

   /// <summary>

   /// 得到分页记录

   /// </summary>

   /// <param name="pageindex">the pageindex.</param>

   /// <param name="pagesize">the pagesize.</param>

   /// <param name="total">总条数</param>

   /// <param name="exp">条件谓词</param>

   /// <param name="orderby">排序,格式如:"id"/"id descending"</param>

   iqueryable<t> find( int pageindex, int pagesize, out int total, expression<func<t, bool >> exp = null , string orderby = "" );

   /// <summary>

   /// 得到分页记录

   /// </summary>

   /// <param name="pageindex">the pageindex.</param>

   /// <param name="pagesize">the pagesize.</param>

   /// <param name="total">总条数</param>

   /// <param name="wherelambda">条件谓词</param>

   /// <param name="orderby">排序,格式如:"id"/"id descending"</param>

   iqueryable<t> find( int pageindex, int pagesize, out int total, string wherelambda = "" , string orderby = "" , params object [] values);

   /// <summary>

   /// 根据过滤条件获取记录数

   /// </summary>

   int getcount(expression<func<t, bool >> exp = null );

   /// <summary>

   /// 添加实体

   /// </summary>

   /// <param name="entity">the entities.</param>

   /// <param name="iscomit">是否提交(true)</param>

   /// <returns></returns>

   int add(t entity, bool iscomit = true );

   /// <summary>

   /// 批量添加

   /// </summary>

   /// <param name="entity">the entities.</param>

   /// <param name="iscomit">是否提交(true)</param>

   int adds(list<t> entitis, bool iscomit = true );

   /// <summary>

   /// 更新实体(会更新实体的所有属性)

   /// </summary>

   /// <param name="entity">the entities.</param>

   /// <param name="iscomit">是否提交(true)</param>

   /// <returns></returns>

   int update(t entity, bool iscomit = true );

   /// <summary>

   /// 删除实体

   /// </summary>

   /// <param name="entity">the entities.</param>

   /// <param name="iscomit">是否提交(true)</param>

   /// <returns></returns>

   int delete(t entity, bool iscomit = true );

   /// <summary>

   /// 实现按需要只更新部分更新

   /// <para>如:update(u =>u.id==1,u =>new user{name="ok"});</para>

   /// </summary>

   /// <param name="where">the where.</param>

   /// <param name="entity">the entity.</param>

   int update(expression<func<t, bool >> where, expression<func<t, t>> entity);

   /// <summary>

   /// 批量按条件删除

   /// </summary>

   /// <param name="exp"></param>

   int delete(expression<func<t, bool >> exp);

   /// <summary>

   /// 对数据库执行给定的 ddl/dml 命令。

   /// </summary>

   /// <param name="sql">sql</param>

   /// <param name="parameters">参数</param>

   /// <returns></returns>

   int executesqlcommand( string sql, params sqlparameter[] parameters);

   /// <summary>

   /// 执行sql查询语句

   /// </summary>

   /// <param name="sql"></param>

   /// <returns></returns>

   dbrawsqlquery< int > executesqlquery( string sql);

   /// <summary>

   /// 执行原始的sql查询

   /// </summary>

   /// <typeparam name="telement">返回的泛型类型</typeparam>

   /// <param name="sql">sql</param>

   /// <param name="parameters">参数</param>

   /// <returns></returns>

   ilist<telement> sqlquery<telement>( string sql, params sqlparameter[] parameters);

   /// <summary>

   /// 开启一个事务

   /// </summary>

   /// <param name="fun"></param>

   bool begintransaction(func< bool > fun);

   /// <summary>

   /// 执行sql语句或存储过程

   /// 返回datatable数据集

   /// </summary>

   /// <param name="sql">sql语句或存储过程 例如:exec usp_procedure</param>

   /// <param name="parameters">参数列表</param>

   /// <returns></returns>

   datatable sqlqueryfordatatable( string sql, dbparameter[] parameters);

   /// <summary>

   /// 返回datatable数据集

   /// </summary>

   /// <param name="proname">存储过程名</param>

   /// <param name="parameters">参数列表</param>

   /// <returns></returns>

   [obsolete( "此方法已过时,请改用sqlqueryfordatatable" )]

   datatable executefordatatable( string proname, idataparameter[] parameters);

  }

然后需要实现这个基类接口,代码如下:

?

public class baserepository<t> : irepository<t> where t : baseentity

   {

     private dbcontext context

     {

       get

       {

         dbcontext db = (dbcontext)callcontext.getdata( "dbcontext" );

         if (db == null )

         {

           db = new dbcontext();

           // db.database.log = o => logginghelper.instance.logging(loglevel.debug, o);

           callcontext.setdata( "dbcontext" , db);

         }

         return db;

       }

     }

     /// <summary>

     /// 根据过滤条件,获取记录

     /// </summary>

     /// <param name="exp"></param>

     /// <param name="isnotracking">(默认不跟踪实体状态)使用notracking的查询会在性能方面得到改善</param>

     /// <returns></returns>

     public iqueryable<t> find(expression<func<t, bool >> exp = null , bool isnotracking = true )

     {

       return filter(exp, isnotracking);

     }

     /// <summary>

     /// 根据过滤条件,获取记录

     /// </summary>

     /// <param name="wherelambda"></param>

     /// <param name="isnotracking">(默认不跟踪实体状态)使用notracking的查询会在性能方面得到改善</param>

     /// <param name="values"></param>

     /// <returns></returns>

     public iqueryable<t> find( string wherelambda = null , bool isnotracking = true , params object [] values)

     {

       return filter(wherelambda, isnotracking, values);

     }

     /// <summary>

     /// 判断记录是否存在

     /// </summary>

     /// <param name="exp"></param>

     /// <returns></returns>

     public bool isexist(expression<func<t, bool >> exp)

     {

       return context. set <t>().any(exp);

     }

     /// <summary>

     /// 查找单个(如果没找到则返回为null)

     /// </summary>

     /// <param name="exp"></param>

     /// <param name="isnotracking">(默认不跟踪实体状态)使用notracking的查询会在性能方面得到改善</param>

     /// <returns></returns>

     public t findsingle(expression<func<t, bool >> exp, bool isnotracking = true )

     {

       return filter(exp, isnotracking).firstordefault();

     }

     /// <summary>

     /// 得到分页记录

     /// </summary>

     /// <param name="pageindex">the pageindex.</param>

     /// <param name="pagesize">the pagesize.</param>

     /// <param name="total">总条数</param>

     /// <param name="exp">条件谓词</param>

     /// <param name="orderby">排序,格式如:"id"/"id descending"</param>

     public iqueryable<t> find( int pageindex, int pagesize, out int total, expression<func<t, bool >> exp = null , string orderby = "" )

     {

       if (pageindex < 1) pageindex = 1;

       var query = filter(exp);

       if (! string .isnullorempty(orderby))

         query = query.orderby(orderby);

       total = query.count();

       ///return query.skip(pagesize * (pageindex - 1)).take(pagesize);

       return null ;

     }

     /// <summary>

     /// 得到分页记录

     /// </summary>

     /// <param name="pageindex">the pageindex.</param>

     /// <param name="pagesize">the pagesize.</param>

     /// <param name="total">总条数</param>

     /// <param name="wherelambda">条件谓词</param>

     /// <param name="orderby">排序,格式如:"id"/"id descending"</param>

     public iqueryable<t> find( int pageindex, int pagesize, out int total, string wherelambda = "" , string orderby = "" , params object [] values)

     {

       if (pageindex < 1) pageindex = 1;

       var query = filter(wherelambda);

       if ( string .isnullorempty(orderby))

         query = query.orderby(orderby);

       total = query.count();

       // return query.skip(pagesize * (pageindex - 1)).take(pagesize);

       return null ;

     }

     /// <summary>

     /// 根据过滤条件获取记录数

     /// </summary>

     public int getcount(expression<func<t, bool >> exp = null )

     {

       return filter(exp).count();

     }

     /// <summary>

     /// 添加书体

     /// </summary>

     /// <param name="entity">the entities.</param>

     /// <param name="iscomit">是否提交(true)</param>

     /// <returns></returns>

     public int add(t entity, bool iscomit = true )

     {

       context.entry<t>(entity).state = system.data.entity.entitystate.added;

       return iscomit ? context.savechanges() : 0;

     }

     /// <summary>

     /// 批量添加

     /// </summary>

     /// <param name="entity">the entities.</param>

     /// <param name="iscomit">是否提交(true)</param>

     public int adds(list<t> entitis, bool iscomit = true )

     {

       foreach (t item in entitis)

       {

         context.entry<t>(item).state = system.data.entity.entitystate.added;

       }

       return iscomit ? context.savechanges() : 0;

     }

     /// <summary>

     /// 更新实体(会更新实体的所有属性)

     /// </summary>

     /// <param name="entity">the entities.</param>

     /// <param name="iscomit">是否提交(true)</param>

     /// <returns></returns>

     public int update(t entity, bool iscomit = true )

     {

       context.entry(entity).state = system.data.entity.entitystate.modified;

       return iscomit ? context.savechanges() : 0;

     }

     /// <summary>

     /// 删除实体

     /// </summary>

     /// <param name="entity">the entities.</param>

     /// <param name="iscomit">是否提交(true)</param>

     /// <returns></returns>

     public int delete(t entity, bool iscomit = true )

     {

       context. set <t>().remove(entity);

       return iscomit ? context.savechanges() : 0;

     }

     /// <summary>

     /// 实现按需要只更新部分更新

     /// <para>如:update(u =>u.id==1,u =>new user{name="ok"});</para>

     /// </summary>

     /// <param name="where">the where.</param>

     /// <param name="entity">the entity.</param>

     public int update(expression<func<t, bool >> where, expression<func<t, t>> entity)

     {

       return context. set <t>().where(where).update(entity);

     }

     /// <summary>

     /// 批量按条件删除

     /// </summary>

     /// <param name="exp"></param>

     public int delete(expression<func<t, bool >> exp)

     {

       return context. set <t>().where(exp).delete();

     }

     /// <summary>

     /// 对数据库执行给定的 ddl/dml 命令。

     /// </summary>

     /// <param name="sql">sql</param>

     /// <param name="parameters">参数</param>

     /// <returns></returns>

     public int executesqlcommand( string sql, params sqlparameter[] parameters)

     {

       return context.database.executesqlcommand(sql, parameters);

     }

     /// <summary>

     /// 执行原始的sql查询

     /// </summary>

     /// <typeparam name="telement">返回的泛型类型</typeparam>

     /// <param name="sql">sql</param>

     /// <param name="parameters">参数</param>

     /// <returns></returns>

     public ilist<telement> sqlquery<telement>( string sql, params sqlparameter[] parameters)

     {

       return context.database.sqlquery<telement>(sql, parameters).tolist();

     }

     public bool begintransaction(func< bool > fun)

     {

       using (var trans = context.database.begintransaction())

       {

         try

         {

           var result = fun();

           trans测试数据mit();

           return result;

         }

         catch (exception)

         {

           trans.rollback();

           return false ;

         }

       }

     }

     private iqueryable<t> filter(expression<func<t, bool >> exp = null , bool isnotracking = true )

     {

       var dbset = context. set <t>().asqueryable();

       if (exp != null )

         dbset = dbset.where(exp);

       if (isnotracking)

         dbset = dbset.asnotracking();

       return dbset;

     }

     private iqueryable<t> filter( string wherelambda = null , bool isnotracking = true , params object [] values)

     {

       var dbset = context. set <t>().asqueryable();

       if (wherelambda != null )

         dbset = dbset.where(wherelambda, values);

       if (isnotracking)

         dbset = dbset.asnotracking();

       return dbset;

     }

     public iqueryable<t> table

     {

       get

       {

         return find(wherelambda: null );

       }

     }

     public iqueryable<tentity> othertable<tentity>() where tentity : baseentity

     {

       return context. set <tentity>().asnotracking().asqueryable();

     }

     public idbset<tentity> set <tentity>() where tentity : baseentity

     {

       return context. set <tentity>();

     }

     /// <summary>

     /// 执行sql查询语句

     /// </summary>

     /// <param name="sql"></param>

     /// <returns></returns>

     public dbrawsqlquery< int > executesqlquery( string sql)

     {

       try

       {

         return context.database.sqlquery< int >(sql);

       }

       catch (exception ex)

       {

         throw ex;

       }

     }

     /// <summary>

     /// 执行sql语句或存储过程

     /// 返回datatable数据集

     /// </summary>

     /// <param name="sql">sql语句或存储过程 例如:exec usp_procedure</param>

     /// <param name="parameters">参数列表</param>

     /// <returns></returns>

     public system.data.datatable sqlqueryfordatatable( string sql, params system.data测试数据mon.dbparameter[] parameters)

     {

       sqlconnection conn = new system.data.sqlclient.sqlconnection();

       try

       {

         conn = (sqlconnection)context.database.connection;

         if (conn.state != connectionstate.open)

         {

           conn.open();

         }

         sqlcommand cmd = new sqlcommand();

         stringbuilder sb = new stringbuilder(sql);

         if (parameters != null && parameters.length > 0)

         {

           if (sql.startswith( "exec " , stringcomparison.ordinalignorecase))

             sb.appendformat( " {0}" , string .join( "," , parameters.select(o => o.parametername).toarray()));

           foreach (var item in parameters)

           {

             cmd.parameters.add(item);

           }

         }

         cmd.connection = conn;

         cmd测试数据mandtext = sb.tostring();

         sqldataadapter adapter = new sqldataadapter(cmd);

         datatable table = new datatable();

         adapter.fill(table);

         conn.close(); //连接需要关闭

         return table;

       }

       catch (exception ex)

       {

         throw ex;

       }

       finally

       {

         if (conn.state == connectionstate.open)

           conn.close();

       }

     }

     /// <summary>

     /// 返回datatable数据集

     /// </summary>

     /// <param name="proname">存储过程名</param>

     /// <param name="parameters">参数列表</param>

     /// <returns></returns>

     [obsolete( "此方法已过时,请改用sqlqueryfordatatable" )]

     public system.data.datatable executefordatatable( string proname, idataparameter[] parameters)

     {

       try

       {

         sqlconnection conn = new system.data.sqlclient.sqlconnection();

         conn.connectionstring = context.database.connection.connectionstring;

         if (conn.state != connectionstate.open)

         {

           conn.open();

         }

         sqlcommand cmd = new sqlcommand(proname, conn);

         cmd测试数据mandtype = commandtype.storedprocedure;

         if (parameters != null && parameters.length > 0)

         {

           foreach (var item in parameters)

           {

             cmd.parameters.add(item);

           }

         }

         sqldataadapter adapter = new sqldataadapter(cmd);

         datatable table = new datatable();

         adapter.fill(table);

         return table;

       }

       catch (exception ex)

       {

         throw ex;

       }

     }

   }

注意,我们在

这个实现类中定义了一个私有方法,指明了数据库访问的上下文dbcontext

dbcontext类如下:

?

public class dbcontext : system.data.entity.dbcontext

   {

      static dbcontext()

     {

       //database.setinitializer(new createdatabaseifnotexists<personaldbcontext>());

     }

      public dbcontext()

       : base ( "name=dbcontext" )

     {

     }

     protected override void onmodelcreating(dbmodelbuilder modelbuilder)

     {

       var typestoregister = assembly.getexecutingassembly().gettypes()

       .where(type => ! string .isnullorempty(type. namespace ))

       .where(type => type.basetype != null && type.basetype.isgenerictype &&

         type.basetype.getgenerictypedefinition() == typeof (entitytypeconfiguration<>));

       foreach (var type in typestoregister)

       {

         dynamic configurationinstance = activator.createinstance(type);

         modelbuilder.configurations.add(configurationinstance);

       }

     }

   }

我们将name=dbcontext 意思是去寻找webconfig中具有相同名称的值 ,所以,我们在配置文件中配置该项如下:

再configuration节点下面新建

?

<connectionstrings>

   <add name= "dbcontext" providername= "system.data.sqlclient" connectionstring= "server=.;database=test;uid=sa;pwd=sa;" />

  </connectionstrings>

忘了说,这里对实现类中的一些扩展方法做了延伸,新建一个dynamicqueryable类,代码如下:

?

public static class dynamicqueryable

   {

     public static iqueryable<t> where<t>( this iqueryable<t> source, string predicate, params object [] values)

     {

       return (iqueryable<t>)where((iqueryable)source, predicate, values);

     }

     public static iqueryable where( this iqueryable source, string predicate, params object [] values)

     {

       if (source == null ) throw new argumentnullexception( "source" );

       if (predicate == null ) throw new argumentnullexception( "predicate" );

       lambdaexpression lambda = dynamicexpression.parselambda(source.elementtype, typeof ( bool ), predicate, values);

       return source.provider.createquery(

         expression.call(

           typeof (queryable), "where" ,

           new type[] { source.elementtype },

           source.expression, expression.quote(lambda)));

     }

     public static iqueryable select( this iqueryable source, string selector, params object [] values)

     {

       if (source == null ) throw new argumentnullexception( "source" );

       if (selector == null ) throw new argumentnullexception( "selector" );

       lambdaexpression lambda = dynamicexpression.parselambda(source.elementtype, null , selector, values);

       return source.provider.createquery(

         expression.call(

           typeof (queryable), "select" ,

           new type[] { source.elementtype, lambda.body.type },

           source.expression, expression.quote(lambda)));

     }

     public static iqueryable<dynamic> select<t>( this iqueryable<t> source, string selector, params object [] values)

     {

       return (iqueryable<dynamic>)select((iqueryable)source, selector, values);

     }

     public static iqueryable<t> orderby<t>( this iqueryable<t> source, string ordering, params object [] values)

     {

       return (iqueryable<t>)orderby((iqueryable)source, ordering, values);

     }

     public static iqueryable<t> thenby<t>( this iqueryable<t> source, string ordering, params object [] values)

     {

       return (iqueryable<t>)thenby((iqueryable)source, ordering, values);

     }

     public static iqueryable thenby( this iqueryable source, string ordering, params object [] values)

     {

       if (source == null ) throw new argumentnullexception( "source" );

       if (ordering == null ) throw new argumentnullexception( "ordering" );

       parameterexpression[] parameters = new parameterexpression[] {

         expression.parameter(source.elementtype, "" ) };

       expressionparser parser = new expressionparser(parameters, ordering, values);

       ienumerable<dynamicordering> orderings = parser.parseordering();

       expression queryexpr = source.expression;

       string methodasc = "thenby" ;

       string methoddesc = "thenbydescending" ;

       foreach (dynamicordering o in orderings)

       {

         queryexpr = expression.call(

           typeof (queryable), o.ascending ? methodasc : methoddesc,

           new type[] { source.elementtype, o.selector.type },

           queryexpr, expression.quote(expression.lambda(o.selector, parameters)));

       }

       return source.provider.createquery(queryexpr);

     }

     public static iqueryable orderby( this iqueryable source, string ordering, params object [] values)

     {

       if (source == null ) throw new argumentnullexception( "source" );

       if (ordering == null ) throw new argumentnullexception( "ordering" );

       parameterexpression[] parameters = new parameterexpression[] {

         expression.parameter(source.elementtype, "" ) };

       expressionparser parser = new expressionparser(parameters, ordering, values);

       ienumerable<dynamicordering> orderings = parser.parseordering();

       expression queryexpr = source.expression;

       string methodasc = "orderby" ;

       string methoddesc = "orderbydescending" ;

       foreach (dynamicordering o in orderings)

       {

         queryexpr = expression.call(

           typeof (queryable), o.ascending ? methodasc : methoddesc,

           new type[] { source.elementtype, o.selector.type },

           queryexpr, expression.quote(expression.lambda(o.selector, parameters)));

         methodasc = "thenby" ;

         methoddesc = "thenbydescending" ;

       }

       return source.provider.createquery(queryexpr);

     }

     public static iqueryable<t> orderby<t>( this iqueryable<t> source, string propertyname, bool ascending)

       where t : class

     {

       type type = typeof (t);

       propertyinfo property = type.getproperty(propertyname);

       if (property == null )

         throw new argumentexception( "propertyname" , "not exist" );

       parameterexpression param = expression.parameter(type, "p" );

       expression propertyaccessexpression = expression.makememberaccess(param, property);

       lambdaexpression orderbyexpression = expression.lambda(propertyaccessexpression, param);

       string methodname = ascending ? "orderby" : "orderbydescending" ;

       methodcallexpression resultexp = expression.call( typeof (queryable), methodname,

         new type[] { type, property.propertytype }, source.expression, expression.quote(orderbyexpression));

       return source.provider.createquery<t>(resultexp);

     }

     public static iqueryable take( this iqueryable source, int count)

     {

       if (source == null ) throw new argumentnullexception( "source" );

       return source.provider.createquery(

         expression.call(

           typeof (queryable), "take" ,

           new type[] { source.elementtype },

           source.expression, expression.constant(count)));

     }

     public static iqueryable skip( this iqueryable source, int count)

     {

       if (source == null ) throw new argumentnullexception( "source" );

       return source.provider.createquery(

         expression.call(

           typeof (queryable), "skip" ,

           new type[] { source.elementtype },

           source.expression, expression.constant(count)));

     }

     public static iqueryable groupby( this iqueryable source, string keyselector, string elementselector, params object [] values)

     {

       if (source == null ) throw new argumentnullexception( "source" );

       if (keyselector == null ) throw new argumentnullexception( "keyselector" );

       if (elementselector == null ) throw new argumentnullexception( "elementselector" );

       lambdaexpression keylambda = dynamicexpression.parselambda(source.elementtype, null , keyselector, values);

       lambdaexpression elementlambda = dynamicexpression.parselambda(source.elementtype, null , elementselector, values);

       return source.provider.createquery(

         expression.call(

           typeof (queryable), "groupby" ,

           new type[] { source.elementtype, keylambda.body.type, elementlambda.body.type },

           source.expression, expression.quote(keylambda), expression.quote(elementlambda)));

     }

     public static bool any( this iqueryable source)

     {

       if (source == null ) throw new argumentnullexception( "source" );

       return ( bool )source.provider.execute(

         expression.call(

           typeof (queryable), "any" ,

           new type[] { source.elementtype }, source.expression));

     }

     public static int count( this iqueryable source)

     {

       if (source == null ) throw new argumentnullexception( "source" );

       return ( int )source.provider.execute(

         expression.call(

           typeof (queryable), "count" ,

           new type[] { source.elementtype }, source.expression));

     }

   }

   public abstract class dynamicclass

   {

     public override string tostring()

     {

       propertyinfo[] props = this .gettype().getproperties(bindingflags.instance | bindingflags. public );

       stringbuilder sb = new stringbuilder();

       sb.append( "{" );

       for ( int i = 0; i < props.length; i++)

       {

         if (i > 0) sb.append( ", " );

         sb.append(props[i].name);

         sb.append( "=" );

         sb.append(props[i].getvalue( this , null ));

       }

       sb.append( "}" );

       return sb.tostring();

     }

   }

   public class dynamicproperty

   {

     string name;

     type type;

     public dynamicproperty( string name, type type)

     {

       if (name == null ) throw new argumentnullexception( "name" );

       if (type == null ) throw new argumentnullexception( "type" );

       this .name = name;

       this .type = type;

     }

     public string name

     {

       get { return name; }

     }

     public type type

     {

       get { return type; }

     }

   }

   public static class dynamicexpression

   {

     public static expression parse(type resulttype, string expression, params object [] values)

     {

       expressionparser parser = new expressionparser( null , expression, values);

       return parser.parse(resulttype);

     }

     public static lambdaexpression parselambda(type ittype, type resulttype, string expression, params object [] values)

     {

       return parselambda( new parameterexpression[] { expression.parameter(ittype, "" ) }, resulttype, expression, values);

     }

     public static lambdaexpression parselambda(parameterexpression[] parameters, type resulttype, string expression, params object [] values)

     {

       expressionparser parser = new expressionparser(parameters, expression, values);

       return expression.lambda(parser.parse(resulttype), parameters);

     }

     public static expression<func<t, s>> parselambda<t, s>( string expression, params object [] values)

     {

       return (expression<func<t, s>>)parselambda( typeof (t), typeof (s), expression, values);

     }

     public static type createclass( params dynamicproperty[] properties)

     {

       return classfactory.instance.getdynamicclass(properties);

     }

     public static type createclass(ienumerable<dynamicproperty> properties)

     {

       return classfactory.instance.getdynamicclass(properties);

     }

   }

   internal class dynamicordering

   {

     public expression selector;

     public bool ascending;

   }

   internal class signature : iequatable<signature>

   {

     public dynamicproperty[] properties;

     public int hashcode;

     public signature(ienumerable<dynamicproperty> properties)

     {

       this .properties = properties.toarray();

       hashcode = 0;

       foreach (dynamicproperty p in properties)

       {

         hashcode ^= p.name.gethashcode() ^ p.type.gethashcode();

       }

     }

     public override int gethashcode()

     {

       return hashcode;

     }

     public override bool equals( object obj)

     {

       return obj is signature ? equals((signature)obj) : false ;

     }

     public bool equals(signature other)

     {

       if (properties.length != other.properties.length) return false ;

       for ( int i = 0; i < properties.length; i++)

       {

         if (properties[i].name != other.properties[i].name ||

           properties[i].type != other.properties[i].type) return false ;

       }

       return true ;

     }

   }

   internal class classfactory

   {

     public static readonly classfactory instance = new classfactory();

     static classfactory() { } // trigger lazy initialization of static fields

     modulebuilder module;

     dictionary<signature, type> classes;

     int classcount;

     readerwriterlock rwlock;

     private classfactory()

     {

       assemblyname name = new assemblyname( "dynamicclasses" );

       assemblybuilder assembly = appdomain.currentdomain.definedynamicassembly(name, assemblybuilderaccess.run);

#if enable_linq_partial_trust

       new reflectionpermission(permissionstate.unrestricted).assert();

#endif

       try

       {

         module = assembly.definedynamicmodule( "module" );

       }

       finally

       {

#if enable_linq_partial_trust

         permissionset.revertassert();

#endif

       }

       classes = new dictionary<signature, type>();

       rwlock = new readerwriterlock();

     }

     public type getdynamicclass(ienumerable<dynamicproperty> properties)

     {

       rwlock.acquirereaderlock(timeout.infinite);

       try

       {

         signature signature = new signature(properties);

         type type;

         if (!classes.trygetvalue(signature, out type))

         {

           type = createdynamicclass(signature.properties);

           classes.add(signature, type);

         }

         return type;

       }

       finally

       {

         rwlock.releasereaderlock();

       }

     }

     type createdynamicclass(dynamicproperty[] properties)

     {

       lockcookie cookie = rwlock.upgradetowriterlock(timeout.infinite);

       try

       {

         string typename = "dynamicclass" + (classcount + 1);

#if enable_linq_partial_trust

         new reflectionpermission(permissionstate.unrestricted).assert();

#endif

         try

         {

           typebuilder tb = this .module.definetype(typename, typeattributes. class |

             typeattributes. public , typeof (dynamicclass));

           fieldinfo[] fields = generateproperties(tb, properties);

           generateequals(tb, fields);

           generategethashcode(tb, fields);

           type result = tb.createtype();

           classcount++;

           return result;

         }

         finally

         {

#if enable_linq_partial_trust

           permissionset.revertassert();

#endif

         }

       }

       finally

       {

         rwlock.downgradefromwriterlock( ref cookie);

       }

     }

     fieldinfo[] generateproperties(typebuilder tb, dynamicproperty[] properties)

     {

       fieldinfo[] fields = new fieldbuilder[properties.length];

       for ( int i = 0; i < properties.length; i++)

       {

         dynamicproperty dp = properties[i];

         fieldbuilder fb = tb.definefield( "_" + dp.name, dp.type, fieldattributes. private );

         propertybuilder pb = tb.defineproperty(dp.name, propertyattributes.hasdefault, dp.type, null );

         methodbuilder mbget = tb.definemethod( "get_" + dp.name,

           methodattributes. public | methodattributes.specialname | methodattributes.hidebysig,

           dp.type, type.emptytypes);

         ilgenerator genget = mbget.getilgenerator();

         genget.emit(opcodes.ldarg_0);

         genget.emit(opcodes.ldfld, fb);

         genget.emit(opcodes.ret);

         methodbuilder mbset = tb.definemethod( "set_" + dp.name,

           methodattributes. public | methodattributes.specialname | methodattributes.hidebysig,

           null , new type[] { dp.type });

         ilgenerator genset = mbset.getilgenerator();

         genset.emit(opcodes.ldarg_0);

         genset.emit(opcodes.ldarg_1);

         genset.emit(opcodes.stfld, fb);

         genset.emit(opcodes.ret);

         pb.setgetmethod(mbget);

         pb.setsetmethod(mbset);

         fields[i] = fb;

       }

       return fields;

     }

     void generateequals(typebuilder tb, fieldinfo[] fields)

     {

       methodbuilder mb = tb.definemethod( "equals" ,

         methodattributes. public | methodattributes.reuseslot |

         methodattributes. virtual | methodattributes.hidebysig,

         typeof ( bool ), new type[] { typeof ( object ) });

       ilgenerator gen = mb.getilgenerator();

       localbuilder other = gen.declarelocal(tb);

       label next = gen.definelabel();

       gen.emit(opcodes.ldarg_1);

       gen.emit(opcodes.isinst, tb);

       gen.emit(opcodes.stloc, other);

       gen.emit(opcodes.ldloc, other);

       gen.emit(opcodes.brtrue_s, next);

       gen.emit(opcodes.ldc_i4_0);

       gen.emit(opcodes.ret);

       gen.marklabel(next);

       foreach (fieldinfo field in fields)

       {

         type ft = field.fieldtype;

         type ct = typeof (equalitycomparer<>).makegenerictype(ft);

         next = gen.definelabel();

         gen.emitcall(opcodes.call, ct.getmethod( "get_default" ), null );

         gen.emit(opcodes.ldarg_0);

         gen.emit(opcodes.ldfld, field);

         gen.emit(opcodes.ldloc, other);

         gen.emit(opcodes.ldfld, field);

         gen.emitcall(opcodes.callvirt, ct.getmethod( "equals" , new type[] { ft, ft }), null );

         gen.emit(opcodes.brtrue_s, next);

         gen.emit(opcodes.ldc_i4_0);

         gen.emit(opcodes.ret);

         gen.marklabel(next);

       }

       gen.emit(opcodes.ldc_i4_1);

       gen.emit(opcodes.ret);

     }

     void generategethashcode(typebuilder tb, fieldinfo[] fields)

     {

       methodbuilder mb = tb.definemethod( "gethashcode" ,

         methodattributes. public | methodattributes.reuseslot |

         methodattributes. virtual | methodattributes.hidebysig,

         typeof ( int ), type.emptytypes);

       ilgenerator gen = mb.getilgenerator();

       gen.emit(opcodes.ldc_i4_0);

       foreach (fieldinfo field in fields)

       {

         type ft = field.fieldtype;

         type ct = typeof (equalitycomparer<>).makegenerictype(ft);

         gen.emitcall(opcodes.call, ct.getmethod( "get_default" ), null );

         gen.emit(opcodes.ldarg_0);

         gen.emit(opcodes.ldfld, field);

         gen.emitcall(opcodes.callvirt, ct.getmethod( "gethashcode" , new type[] { ft }), null );

         gen.emit(opcodes.xor);

       }

       gen.emit(opcodes.ret);

     }

   }

   public sealed class parseexception : exception

   {

     int position;

     public parseexception( string message, int position)

       : base (message)

     {

       this .position = position;

     }

     public int position

     {

       get { return position; }

     }

     public override string tostring()

     {

       return string .format(res.parseexceptionformat, message, position);

     }

   }

   internal class expressionparser

   {

     struct token

     {

       public tokenid id;

       public string text;

       public int pos;

     }

     enum tokenid

     {

       unknown,

       end,

       identifier,

       stringliteral,

       integerliteral,

       realliteral,

       exclamation,

       percent,

       amphersand,

       openparen,

       closeparen,

       asterisk,

       plus,

       comma,

       minus,

       dot,

       slash,

       colon,

       lessthan,

       equal,

       greaterthan,

       question,

       openbracket,

       closebracket,

       bar,

       exclamationequal,

       doubleamphersand,

       lessthanequal,

       lessgreater,

       doubleequal,

       greaterthanequal,

       doublebar

     }

     interface ilogicalsignatures

     {

       void f( bool x, bool y);

       void f( bool ? x, bool ? y);

     }

     interface iarithmeticsignatures

     {

       void f( int x, int y);

       void f( uint x, uint y);

       void f( long x, long y);

       void f( ulong x, ulong y);

       void f( float x, float y);

       void f( double x, double y);

       void f( decimal x, decimal y);

       void f( int ? x, int ? y);

       void f( uint ? x, uint ? y);

       void f( long ? x, long ? y);

       void f( ulong ? x, ulong ? y);

       void f( float ? x, float ? y);

       void f( double ? x, double ? y);

       void f( decimal ? x, decimal ? y);

     }

     interface irelationalsignatures : iarithmeticsignatures

     {

       void f( string x, string y);

       void f( char x, char y);

       void f(datetime x, datetime y);

       void f(timespan x, timespan y);

       void f( char ? x, char ? y);

       void f(datetime? x, datetime? y);

       void f(timespan? x, timespan? y);

     }

     interface iequalitysignatures : irelationalsignatures

     {

       void f( bool x, bool y);

       void f( bool ? x, bool ? y);

     }

     interface iaddsignatures : iarithmeticsignatures

     {

       void f(datetime x, timespan y);

       void f(timespan x, timespan y);

       void f(datetime? x, timespan? y);

       void f(timespan? x, timespan? y);

     }

     interface isubtractsignatures : iaddsignatures

     {

       void f(datetime x, datetime y);

       void f(datetime? x, datetime? y);

     }

     interface inegationsignatures

     {

       void f( int x);

       void f( long x);

       void f( float x);

       void f( double x);

       void f( decimal x);

       void f( int ? x);

       void f( long ? x);

       void f( float ? x);

       void f( double ? x);

       void f( decimal ? x);

     }

     interface inotsignatures

     {

       void f( bool x);

       void f( bool ? x);

     }

     interface ienumerablesignatures

     {

       void where( bool predicate);

       void any();

       void any( bool predicate);

       void all( bool predicate);

       void count();

       void count( bool predicate);

       void min( object selector);

       void max( object selector);

       void sum( int selector);

       void sum( int ? selector);

       void sum( long selector);

       void sum( long ? selector);

       void sum( float selector);

       void sum( float ? selector);

       void sum( double selector);

       void sum( double ? selector);

       void sum( decimal selector);

       void sum( decimal ? selector);

       void average( int selector);

       void average( int ? selector);

       void average( long selector);

       void average( long ? selector);

       void average( float selector);

       void average( float ? selector);

       void average( double selector);

       void average( double ? selector);

       void average( decimal selector);

       void average( decimal ? selector);

     }

     static readonly type[] predefinedtypes = {

       typeof ( object ),

       typeof (boolean),

       typeof ( char ),

       typeof ( string ),

       typeof ( sbyte ),

       typeof ( byte ),

       typeof (int16),

       typeof (uint16),

       typeof (int32),

       typeof (uint32),

       typeof (int64),

       typeof (uint64),

       typeof (single),

       typeof ( double ),

       typeof ( decimal ),

       typeof (datetime),

       typeof (timespan),

       typeof (guid),

       typeof (math),

       typeof (convert)

     };

     static readonly expression trueliteral = expression.constant( true );

     static readonly expression falseliteral = expression.constant( false );

     static readonly expression nullliteral = expression.constant( null );

     static readonly string keywordit = "it" ;

     static readonly string keywordiif = "iif" ;

     static readonly string keywordnew = "new" ;

     static dictionary< string , object > keywords;

     dictionary< string , object > symbols;

     idictionary< string , object > externals;

     dictionary<expression, string > literals;

     parameterexpression it;

     string text;

     int textpos;

     int textlen;

     char ch;

     token token;

     public expressionparser(parameterexpression[] parameters, string expression, object [] values)

     {

       if (expression == null ) throw new argumentnullexception( "expression" );

       if (keywords == null ) keywords = createkeywords();

       symbols = new dictionary< string , object >(stringcomparer.ordinalignorecase);

       literals = new dictionary<expression, string >();

       if (parameters != null ) processparameters(parameters);

       if (values != null ) processvalues(values);

       text = expression;

       textlen = text.length;

       settextpos(0);

       nexttoken();

     }

     void processparameters(parameterexpression[] parameters)

     {

       foreach (parameterexpression pe in parameters)

         if (! string .isnullorempty(pe.name))

           addsymbol(pe.name, pe);

       if (parameters.length == 1 && string .isnullorempty(parameters[0].name))

         it = parameters[0];

     }

     void processvalues( object [] values)

     {

       for ( int i = 0; i < values.length; i++)

       {

         object value = values[i];

         if (i == values.length - 1 && value is idictionary< string , object >)

         {

           externals = (idictionary< string , object >)value;

         }

         else

         {

           addsymbol( "@" + i.tostring(system.globalization.cultureinfo.invariantculture), value);

         }

       }

     }

     void addsymbol( string name, object value)

     {

       if (symbols.containskey(name))

         throw parseerror(res.duplicateidentifier, name);

       symbols.add(name, value);

     }

     public expression parse(type resulttype)

     {

       int exprpos = token.pos;

       expression expr = parseexpression();

       if (resulttype != null )

         if ((expr = promoteexpression(expr, resulttype, true )) == null )

           throw parseerror(exprpos, res.expressiontypemismatch, gettypename(resulttype));

       validatetoken(tokenid.end, res.syntaxerror);

       return expr;

     }

#pragma warning disable 0219

     public ienumerable<dynamicordering> parseordering()

     {

       list<dynamicordering> orderings = new list<dynamicordering>();

       while ( true )

       {

         expression expr = parseexpression();

         bool ascending = true ;

         if (tokenidentifieris( "asc" ) || tokenidentifieris( "ascending" ))

         {

           nexttoken();

         }

         else if (tokenidentifieris( "desc" ) || tokenidentifieris( "descending" ))

         {

           nexttoken();

           ascending = false ;

         }

         orderings.add( new dynamicordering { selector = expr, ascending = ascending });

         if (token.id != tokenid测试数据ma) break ;

         nexttoken();

       }

       validatetoken(tokenid.end, res.syntaxerror);

       return orderings;

     }

#pragma warning restore 0219

     // ?: operator

     expression parseexpression()

     {

       int errorpos = token.pos;

       expression expr = parselogicalor();

       if (token.id == tokenid.question)

       {

         nexttoken();

         expression expr1 = parseexpression();

         validatetoken(tokenid.colon, res.colonexpected);

         nexttoken();

         expression expr2 = parseexpression();

         expr = generateconditional(expr, expr1, expr2, errorpos);

       }

       return expr;

     }

     // ||, or operator

     expression parselogicalor()

     {

       expression left = parselogicaland();

       while (token.id == tokenid.doublebar || tokenidentifieris( "or" ))

       {

         token op = token;

         nexttoken();

         expression right = parselogicaland();

         checkandpromoteoperands( typeof (ilogicalsignatures), op.text, ref left, ref right, op.pos);

         left = expression.orelse(left, right);

       }

       return left;

     }

     // &&, and operator

     expression parselogicaland()

     {

       expression left = parsecomparison();

       while (token.id == tokenid.doubleamphersand || tokenidentifieris( "and" ))

       {

         token op = token;

         nexttoken();

         expression right = parsecomparison();

         checkandpromoteoperands( typeof (ilogicalsignatures), op.text, ref left, ref right, op.pos);

         left = expression.andalso(left, right);

       }

       return left;

     }

     // =, ==, !=, <>, >, >=, <, <= operators

     expression parsecomparison()

     {

       expression left = parseadditive();

       while (token.id == tokenid.equal || token.id == tokenid.doubleequal ||

         token.id == tokenid.exclamationequal || token.id == tokenid.lessgreater ||

         token.id == tokenid.greaterthan || token.id == tokenid.greaterthanequal ||

         token.id == tokenid.lessthan || token.id == tokenid.lessthanequal)

       {

         token op = token;

         nexttoken();

         expression right = parseadditive();

         bool isequality = op.id == tokenid.equal || op.id == tokenid.doubleequal ||

           op.id == tokenid.exclamationequal || op.id == tokenid.lessgreater;

         if (isequality && !left.type.isvaluetype && !right.type.isvaluetype)

         {

           if (left.type != right.type)

           {

             if (left.type.isassignablefrom(right.type))

             {

               right = expression.convert(right, left.type);

             }

             else if (right.type.isassignablefrom(left.type))

             {

               left = expression.convert(left, right.type);

             }

             else

             {

               throw incompatibleoperandserror(op.text, left, right, op.pos);

             }

           }

         }

         else if (isenumtype(left.type) || isenumtype(right.type))

         {

           if (left.type != right.type)

           {

             expression e;

             if ((e = promoteexpression(right, left.type, true )) != null )

             {

               right = e;

             }

             else if ((e = promoteexpression(left, right.type, true )) != null )

             {

               left = e;

             }

             else

             {

               throw incompatibleoperandserror(op.text, left, right, op.pos);

             }

           }

         }

         else

         {

           checkandpromoteoperands(isequality ? typeof (iequalitysignatures) : typeof (irelationalsignatures),

             op.text, ref left, ref right, op.pos);

         }

         switch (op.id)

         {

           case tokenid.equal:

           case tokenid.doubleequal:

             left = generateequal(left, right);

             break ;

           case tokenid.exclamationequal:

           case tokenid.lessgreater:

             left = generatenotequal(left, right);

             break ;

           case tokenid.greaterthan:

             left = generategreaterthan(left, right);

             break ;

           case tokenid.greaterthanequal:

             left = generategreaterthanequal(left, right);

             break ;

           case tokenid.lessthan:

             left = generatelessthan(left, right);

             break ;

           case tokenid.lessthanequal:

             left = generatelessthanequal(left, right);

             break ;

         }

       }

       return left;

     }

     // +, -, & operators

     expression parseadditive()

     {

       expression left = parsemultiplicative();

       while (token.id == tokenid.plus || token.id == tokenid.minus ||

         token.id == tokenid.amphersand)

       {

         token op = token;

         nexttoken();

         expression right = parsemultiplicative();

         switch (op.id)

         {

           case tokenid.plus:

             if (left.type == typeof ( string ) || right.type == typeof ( string ))

               goto case tokenid.amphersand;

             checkandpromoteoperands( typeof (iaddsignatures), op.text, ref left, ref right, op.pos);

             left = generateadd(left, right);

             break ;

           case tokenid.minus:

             checkandpromoteoperands( typeof (isubtractsignatures), op.text, ref left, ref right, op.pos);

             left = generatesubtract(left, right);

             break ;

           case tokenid.amphersand:

             left = generatestringconcat(left, right);

             break ;

         }

       }

       return left;

     }

     // *, /, %, mod operators

     expression parsemultiplicative()

     {

       expression left = parseunary();

       while (token.id == tokenid.asterisk || token.id == tokenid.slash ||

         token.id == tokenid.percent || tokenidentifieris( "mod" ))

       {

         token op = token;

         nexttoken();

         expression right = parseunary();

         checkandpromoteoperands( typeof (iarithmeticsignatures), op.text, ref left, ref right, op.pos);

         switch (op.id)

         {

           case tokenid.asterisk:

             left = expression.multiply(left, right);

             break ;

           case tokenid.slash:

             left = expression.divide(left, right);

             break ;

           case tokenid.percent:

           case tokenid.identifier:

             left = expression.modulo(left, right);

             break ;

         }

       }

       return left;

     }

     // -, !, not unary operators

     expression parseunary()

     {

       if (token.id == tokenid.minus || token.id == tokenid.exclamation ||

         tokenidentifieris( "not" ))

       {

         token op = token;

         nexttoken();

         if (op.id == tokenid.minus && (token.id == tokenid.integerliteral ||

           token.id == tokenid.realliteral))

         {

           token.text = "-" + token.text;

           token.pos = op.pos;

           return parseprimary();

         }

         expression expr = parseunary();

         if (op.id == tokenid.minus)

         {

           checkandpromoteoperand( typeof (inegationsignatures), op.text, ref expr, op.pos);

           expr = expression.negate(expr);

         }

         else

         {

           checkandpromoteoperand( typeof (inotsignatures), op.text, ref expr, op.pos);

           expr = expression.not(expr);

         }

         return expr;

       }

       return parseprimary();

     }

     expression parseprimary()

     {

       expression expr = parseprimarystart();

       while ( true )

       {

         if (token.id == tokenid.dot)

         {

           nexttoken();

           expr = parsememberaccess( null , expr);

         }

         else if (token.id == tokenid.openbracket)

         {

           expr = parseelementaccess(expr);

         }

         else

         {

           break ;

         }

       }

       return expr;

     }

     expression parseprimarystart()

     {

       switch (token.id)

       {

         case tokenid.identifier:

           return parseidentifier();

         case tokenid.stringliteral:

           return parsestringliteral();

         case tokenid.integerliteral:

           return parseintegerliteral();

         case tokenid.realliteral:

           return parserealliteral();

         case tokenid.openparen:

           return parseparenexpression();

         default :

           throw parseerror(res.expressionexpected);

       }

     }

     expression parsestringliteral()

     {

       validatetoken(tokenid.stringliteral);

       char quote = token.text[0];

       string s = token.text.substring(1, token.text.length - 2);

       int start = 0;

       while ( true )

       {

         int i = s.indexof(quote, start);

         if (i < 0) break ;

         s = s.remove(i, 1);

         start = i + 1;

       }

       //if (quote == '\'') {

       //  if (s.length != 1)

       //    throw parseerror(res.invalidcharacterliteral);

       //  nexttoken();

       //  return createliteral(s[0], s);

       //}

       nexttoken();

       return createliteral(s, s);

     }

     expression parseintegerliteral()

     {

       validatetoken(tokenid.integerliteral);

       string text = token.text;

       if (text[0] != '-' )

       {

         ulong value;

         if (!uint64.tryparse(text, out value))

           throw parseerror(res.invalidintegerliteral, text);

         nexttoken();

         if (value <= ( ulong )int32.maxvalue) return createliteral(( int )value, text);

         if (value <= ( ulong )uint32.maxvalue) return createliteral(( uint )value, text);

         if (value <= ( ulong )int64.maxvalue) return createliteral(( long )value, text);

         return createliteral(value, text);

       }

       else

       {

         long value;

         if (!int64.tryparse(text, out value))

           throw parseerror(res.invalidintegerliteral, text);

         nexttoken();

         if (value >= int32.minvalue && value <= int32.maxvalue)

           return createliteral(( int )value, text);

         return createliteral(value, text);

       }

     }

     expression parserealliteral()

     {

       validatetoken(tokenid.realliteral);

       string text = token.text;

       object value = null ;

       char last = text[text.length - 1];

       if (last == 'f' || last == 'f' )

       {

         float f;

         if (single.tryparse(text.substring(0, text.length - 1), out f)) value = f;

       }

       else

       {

         double d;

         if ( double .tryparse(text, out d)) value = d;

       }

       if (value == null ) throw parseerror(res.invalidrealliteral, text);

       nexttoken();

       return createliteral(value, text);

     }

     expression createliteral( object value, string text)

     {

       constantexpression expr = expression.constant(value);

       literals.add(expr, text);

       return expr;

     }

     expression parseparenexpression()

     {

       validatetoken(tokenid.openparen, res.openparenexpected);

       nexttoken();

       expression e = parseexpression();

       validatetoken(tokenid.closeparen, res.closeparenoroperatorexpected);

       nexttoken();

       return e;

     }

     expression parseidentifier()

     {

       validatetoken(tokenid.identifier);

       object value;

       if (keywords.trygetvalue(token.text, out value))

       {

         if (value is type) return parsetypeaccess((type)value);

         if (value == ( object )keywordit) return parseit();

         if (value == ( object )keywordiif) return parseiif();

         if (value == ( object )keywordnew) return parsenew();

         nexttoken();

         return (expression)value;

       }

       if (symbols.trygetvalue(token.text, out value) ||

         externals != null && externals.trygetvalue(token.text, out value))

       {

         expression expr = value as expression;

         if (expr == null )

         {

           expr = expression.constant(value);

         }

         else

         {

           lambdaexpression lambda = expr as lambdaexpression;

           if (lambda != null ) return parselambdainvocation(lambda);

         }

         nexttoken();

         return expr;

       }

       if (it != null ) return parsememberaccess( null , it);

       throw parseerror(res.unknownidentifier, token.text);

     }

     expression parseit()

     {

       if (it == null )

         throw parseerror(res.noitinscope);

       nexttoken();

       return it;

     }

     expression parseiif()

     {

       int errorpos = token.pos;

       nexttoken();

       expression[] args = parseargumentlist();

       if (args.length != 3)

         throw parseerror(errorpos, res.iifrequiresthreeargs);

       return generateconditional(args[0], args[1], args[2], errorpos);

     }

     expression generateconditional(expression test, expression expr1, expression expr2, int errorpos)

     {

       if (test.type != typeof ( bool ))

         throw parseerror(errorpos, res.firstexprmustbebool);

       if (expr1.type != expr2.type)

       {

         expression expr1as2 = expr2 != nullliteral ? promoteexpression(expr1, expr2.type, true ) : null ;

         expression expr2as1 = expr1 != nullliteral ? promoteexpression(expr2, expr1.type, true ) : null ;

         if (expr1as2 != null && expr2as1 == null )

         {

           expr1 = expr1as2;

         }

         else if (expr2as1 != null && expr1as2 == null )

         {

           expr2 = expr2as1;

         }

         else

         {

           string type1 = expr1 != nullliteral ? expr1.type.name : "null" ;

           string type2 = expr2 != nullliteral ? expr2.type.name : "null" ;

           if (expr1as2 != null && expr2as1 != null )

             throw parseerror(errorpos, res.bothtypesconverttoother, type1, type2);

           throw parseerror(errorpos, res.neithertypeconvertstoother, type1, type2);

         }

       }

       return expression.condition(test, expr1, expr2);

     }

     expression parsenew()

     {

       nexttoken();

       validatetoken(tokenid.openparen, res.openparenexpected);

       nexttoken();

       list<dynamicproperty> properties = new list<dynamicproperty>();

       list<expression> expressions = new list<expression>();

       while ( true )

       {

         int exprpos = token.pos;

         expression expr = parseexpression();

         string propname;

         if (tokenidentifieris( "as" ))

         {

           nexttoken();

           propname = getidentifier();

           nexttoken();

         }

         else

         {

           memberexpression me = expr as memberexpression;

           if (me == null ) throw parseerror(exprpos, res.missingasclause);

           propname = me.member.name;

         }

         expressions.add(expr);

         properties.add( new dynamicproperty(propname, expr.type));

         if (token.id != tokenid测试数据ma) break ;

         nexttoken();

       }

       validatetoken(tokenid.closeparen, res.closeparenorcommaexpected);

       nexttoken();

       type type = dynamicexpression.createclass(properties);

       memberbinding[] bindings = new memberbinding[properties.count];

       for ( int i = 0; i < bindings.length; i++)

         bindings[i] = expression.bind(type.getproperty(properties[i].name), expressions[i]);

       return expression.memberinit(expression. new (type), bindings);

     }

     expression parselambdainvocation(lambdaexpression lambda)

     {

       int errorpos = token.pos;

       nexttoken();

       expression[] args = parseargumentlist();

       methodbase method;

       if (findmethod(lambda.type, "invoke" , false , args, out method) != 1)

         throw parseerror(errorpos, res.argsincompatiblewithlambda);

       return expression.invoke(lambda, args);

     }

     expression parsetypeaccess(type type)

     {

       int errorpos = token.pos;

       nexttoken();

       if (token.id == tokenid.question)

       {

         if (!type.isvaluetype || isnullabletype(type))

           throw parseerror(errorpos, res.typehasnonullableform, gettypename(type));

         type = typeof (nullable<>).makegenerictype(type);

         nexttoken();

       }

       if (token.id == tokenid.openparen)

       {

         expression[] args = parseargumentlist();

         methodbase method;

         switch (findbestmethod(type.getconstructors(), args, out method))

         {

           case 0:

             if (args.length == 1)

               return generateconversion(args[0], type, errorpos);

             throw parseerror(errorpos, res.nomatchingconstructor, gettypename(type));

           case 1:

             return expression. new ((constructorinfo)method, args);

           default :

             throw parseerror(errorpos, res.ambiguousconstructorinvocation, gettypename(type));

         }

       }

       validatetoken(tokenid.dot, res.dotoropenparenexpected);

       nexttoken();

       return parsememberaccess(type, null );

     }

     expression generateconversion(expression expr, type type, int errorpos)

     {

       type exprtype = expr.type;

       if (exprtype == type) return expr;

       if (exprtype.isvaluetype && type.isvaluetype)

       {

         if ((isnullabletype(exprtype) || isnullabletype(type)) &&

           getnonnullabletype(exprtype) == getnonnullabletype(type))

           return expression.convert(expr, type);

         if ((isnumerictype(exprtype) || isenumtype(exprtype)) &&

           (isnumerictype(type)) || isenumtype(type))

           return expression.convertchecked(expr, type);

       }

       if (exprtype.isassignablefrom(type) || type.isassignablefrom(exprtype) ||

         exprtype.isinterface || type.isinterface)

         return expression.convert(expr, type);

       throw parseerror(errorpos, res.cannotconvertvalue,

         gettypename(exprtype), gettypename(type));

     }

     expression parsememberaccess(type type, expression instance)

     {

       if (instance != null ) type = instance.type;

       int errorpos = token.pos;

       string id = getidentifier();

       nexttoken();

       if (token.id == tokenid.openparen)

       {

         if (instance != null && type != typeof ( string ))

         {

           type enumerabletype = findgenerictype( typeof (ienumerable<>), type);

           if (enumerabletype != null )

           {

             type elementtype = enumerabletype.getgenericarguments()[0];

             return parseaggregate(instance, elementtype, id, errorpos);

           }

         }

         expression[] args = parseargumentlist();

         methodbase mb;

         switch (findmethod(type, id, instance == null , args, out mb))

         {

           case 0:

             throw parseerror(errorpos, res.noapplicablemethod,

               id, gettypename(type));

           case 1:

             methodinfo method = (methodinfo)mb;

             if (!ispredefinedtype(method.declaringtype))

               throw parseerror(errorpos, res.methodsareinaccessible, gettypename(method.declaringtype));

             if (method.returntype == typeof ( void ))

               throw parseerror(errorpos, res.methodisvoid,

                 id, gettypename(method.declaringtype));

             return expression.call(instance, (methodinfo)method, args);

           default :

             throw parseerror(errorpos, res.ambiguousmethodinvocation,

               id, gettypename(type));

         }

       }

       else

       {

         memberinfo member = findpropertyorfield(type, id, instance == null );

         if (member == null )

           throw parseerror(errorpos, res.unknownpropertyorfield,

             id, gettypename(type));

         return member is propertyinfo ?

           expression.property(instance, (propertyinfo)member) :

           expression.field(instance, (fieldinfo)member);

       }

     }

     static type findgenerictype(type generic, type type)

     {

       while (type != null && type != typeof ( object ))

       {

         if (type.isgenerictype && type.getgenerictypedefinition() == generic) return type;

         if (generic.isinterface)

         {

           foreach (type intftype in type.getinterfaces())

           {

             type found = findgenerictype(generic, intftype);

             if (found != null ) return found;

           }

         }

         type = type.basetype;

       }

       return null ;

     }

     expression parseaggregate(expression instance, type elementtype, string methodname, int errorpos)

     {

       parameterexpression outerit = it;

       parameterexpression innerit = expression.parameter(elementtype, "" );

       it = innerit;

       expression[] args = parseargumentlist();

       it = outerit;

       methodbase signature;

       if (findmethod( typeof (ienumerablesignatures), methodname, false , args, out signature) != 1)

         throw parseerror(errorpos, res.noapplicableaggregate, methodname);

       type[] typeargs;

       if (signature.name == "min" || signature.name == "max" )

       {

         typeargs = new type[] { elementtype, args[0].type };

       }

       else

       {

         typeargs = new type[] { elementtype };

       }

       if (args.length == 0)

       {

         args = new expression[] { instance };

       }

       else

       {

         args = new expression[] { instance, expression.lambda(args[0], innerit) };

       }

       return expression.call( typeof (enumerable), signature.name, typeargs, args);

     }

     expression[] parseargumentlist()

     {

       validatetoken(tokenid.openparen, res.openparenexpected);

       nexttoken();

       expression[] args = token.id != tokenid.closeparen ? parsearguments() : new expression[0];

       validatetoken(tokenid.closeparen, res.closeparenorcommaexpected);

       nexttoken();

       return args;

     }

     expression[] parsearguments()

     {

       list<expression> arglist = new list<expression>();

       while ( true )

       {

         arglist.add(parseexpression());

         if (token.id != tokenid测试数据ma) break ;

         nexttoken();

       }

       return arglist.toarray();

     }

     expression parseelementaccess(expression expr)

     {

       int errorpos = token.pos;

       validatetoken(tokenid.openbracket, res.openparenexpected);

       nexttoken();

       expression[] args = parsearguments();

       validatetoken(tokenid.closebracket, res.closebracketorcommaexpected);

       nexttoken();

       if (expr.type.isarray)

       {

         if (expr.type.getarrayrank() != 1 || args.length != 1)

           throw parseerror(errorpos, res.cannotindexmultidimarray);

         expression index = promoteexpression(args[0], typeof ( int ), true );

         if (index == null )

           throw parseerror(errorpos, res.invalidindex);

         return expression.arrayindex(expr, index);

       }

       else

       {

         methodbase mb;

         switch (findindexer(expr.type, args, out mb))

         {

           case 0:

             throw parseerror(errorpos, res.noapplicableindexer,

               gettypename(expr.type));

           case 1:

             return expression.call(expr, (methodinfo)mb, args);

           default :

             throw parseerror(errorpos, res.ambiguousindexerinvocation,

               gettypename(expr.type));

         }

       }

     }

     static bool ispredefinedtype(type type)

     {

       foreach (type t in predefinedtypes) if (t == type) return true ;

       return false ;

     }

     static bool isnullabletype(type type)

     {

       return type.isgenerictype && type.getgenerictypedefinition() == typeof (nullable<>);

     }

     static type getnonnullabletype(type type)

     {

       return isnullabletype(type) ? type.getgenericarguments()[0] : type;

     }

     static string gettypename(type type)

     {

       type basetype = getnonnullabletype(type);

       string s = basetype.name;

       if (type != basetype) s += '?' ;

       return s;

     }

     static bool isnumerictype(type type)

     {

       return getnumerictypekind(type) != 0;

     }

     static bool issignedintegraltype(type type)

     {

       return getnumerictypekind(type) == 2;

     }

     static bool isunsignedintegraltype(type type)

     {

       return getnumerictypekind(type) == 3;

     }

     static int getnumerictypekind(type type)

     {

       type = getnonnullabletype(type);

       if (type.isenum) return 0;

       switch (type.gettypecode(type))

       {

         case typecode. char :

         case typecode.single:

         case typecode. double :

         case typecode. decimal :

           return 1;

         case typecode. sbyte :

         case typecode.int16:

         case typecode.int32:

         case typecode.int64:

           return 2;

         case typecode. byte :

         case typecode.uint16:

         case typecode.uint32:

         case typecode.uint64:

           return 3;

         default :

           return 0;

       }

     }

     static bool isenumtype(type type)

     {

       return getnonnullabletype(type).isenum;

     }

     void checkandpromoteoperand(type signatures, string opname, ref expression expr, int errorpos)

     {

       expression[] args = new expression[] { expr };

       methodbase method;

       if (findmethod(signatures, "f" , false , args, out method) != 1)

         throw parseerror(errorpos, res.incompatibleoperand,

           opname, gettypename(args[0].type));

       expr = args[0];

     }

     void checkandpromoteoperands(type signatures, string opname, ref expression left, ref expression right, int errorpos)

     {

       expression[] args = new expression[] { left, right };

       methodbase method;

       if (findmethod(signatures, "f" , false , args, out method) != 1)

         throw incompatibleoperandserror(opname, left, right, errorpos);

       left = args[0];

       right = args[1];

     }

     exception incompatibleoperandserror( string opname, expression left, expression right, int pos)

     {

       return parseerror(pos, res.incompatibleoperands,

         opname, gettypename(left.type), gettypename(right.type));

     }

     memberinfo findpropertyorfield(type type, string membername, bool staticaccess)

     {

       bindingflags flags = bindingflags. public | bindingflags.declaredonly |

         (staticaccess ? bindingflags. static : bindingflags.instance);

       foreach (type t in selfandbasetypes(type))

       {

         memberinfo[] members = t.findmembers(membertypes.property | membertypes.field,

           flags, type.filternameignorecase, membername);

         if (members.length != 0) return members[0];

       }

       return null ;

     }

     int findmethod(type type, string methodname, bool staticaccess, expression[] args, out methodbase method)

     {

       bindingflags flags = bindingflags. public | bindingflags.declaredonly |

         (staticaccess ? bindingflags. static : bindingflags.instance);

       foreach (type t in selfandbasetypes(type))

       {

         memberinfo[] members = t.findmembers(membertypes.method,

           flags, type.filternameignorecase, methodname);

         int count = findbestmethod(members.cast<methodbase>(), args, out method);

         if (count != 0) return count;

       }

       method = null ;

       return 0;

     }

     int findindexer(type type, expression[] args, out methodbase method)

     {

       foreach (type t in selfandbasetypes(type))

       {

         memberinfo[] members = t.getdefaultmembers();

         if (members.length != 0)

         {

           ienumerable<methodbase> methods = members.

             oftype<propertyinfo>().

             select(p => (methodbase)p.getgetmethod()).

             where(m => m != null );

           int count = findbestmethod(methods, args, out method);

           if (count != 0) return count;

         }

       }

       method = null ;

       return 0;

     }

     static ienumerable<type> selfandbasetypes(type type)

     {

       if (type.isinterface)

       {

         list<type> types = new list<type>();

         addinterface(types, type);

         return types;

       }

       return selfandbaseclasses(type);

     }

     static ienumerable<type> selfandbaseclasses(type type)

     {

       while (type != null )

       {

         yield return type;

         type = type.basetype;

       }

     }

     static void addinterface(list<type> types, type type)

     {

       if (!types.contains(type))

       {

         types.add(type);

         foreach (type t in type.getinterfaces()) addinterface(types, t);

       }

     }

     class methoddata

     {

       public methodbase methodbase;

       public parameterinfo[] parameters;

       public expression[] args;

     }

     int findbestmethod(ienumerable<methodbase> methods, expression[] args, out methodbase method)

     {

       methoddata[] applicable = methods.

         select(m => new methoddata { methodbase = m, parameters = m.getparameters() }).

         where(m => isapplicable(m, args)).

         toarray();

       if (applicable.length > 1)

       {

         applicable = applicable.

           where(m => applicable.all(n => m == n || isbetterthan(args, m, n))).

           toarray();

       }

       if (applicable.length == 1)

       {

         methoddata md = applicable[0];

         for ( int i = 0; i < args.length; i++) args[i] = md.args[i];

         method = md.methodbase;

       }

       else

       {

         method = null ;

       }

       return applicable.length;

     }

     bool isapplicable(methoddata method, expression[] args)

     {

       if (method.parameters.length != args.length) return false ;

       expression[] promotedargs = new expression[args.length];

       for ( int i = 0; i < args.length; i++)

       {

         parameterinfo pi = method.parameters[i];

         if (pi.isout) return false ;

         expression promoted = promoteexpression(args[i], pi.parametertype, false );

         if (promoted == null ) return false ;

         promotedargs[i] = promoted;

       }

       method.args = promotedargs;

       return true ;

     }

     expression promoteexpression(expression expr, type type, bool exact)

     {

       if (expr.type == type) return expr;

       if (expr is constantexpression)

       {

         constantexpression ce = (constantexpression)expr;

         if (ce == nullliteral)

         {

           if (!type.isvaluetype || isnullabletype(type))

             return expression.constant( null , type);

         }

         else

         {

           string text;

           if (literals.trygetvalue(ce, out text))

           {

             type target = getnonnullabletype(type);

             object value = null ;

             switch (type.gettypecode(ce.type))

             {

               case typecode.int32:

               case typecode.uint32:

               case typecode.int64:

               case typecode.uint64:

                 value = parsenumber(text, target);

                 break ;

               case typecode. double :

                 if (target == typeof ( decimal )) value = parsenumber(text, target);

                 break ;

               case typecode. string :

                 value = parseenum(text, target);

                 break ;

             }

             if (value != null )

               return expression.constant(value, type);

           }

         }

       }

       if (iscompatiblewith(expr.type, type))

       {

         if (type.isvaluetype || exact) return expression.convert(expr, type);

         return expr;

       }

       return null ;

     }

     static object parsenumber( string text, type type)

     {

       switch (type.gettypecode(getnonnullabletype(type)))

       {

         case typecode. sbyte :

           sbyte sb;

           if ( sbyte .tryparse(text, out sb)) return sb;

           break ;

         case typecode. byte :

           byte b;

           if ( byte .tryparse(text, out b)) return b;

           break ;

         case typecode.int16:

           short s;

           if ( short .tryparse(text, out s)) return s;

           break ;

         case typecode.uint16:

           ushort us;

           if ( ushort .tryparse(text, out us)) return us;

           break ;

         case typecode.int32:

           int i;

           if ( int .tryparse(text, out i)) return i;

           break ;

         case typecode.uint32:

           uint ui;

           if ( uint .tryparse(text, out ui)) return ui;

           break ;

         case typecode.int64:

           long l;

           if ( long .tryparse(text, out l)) return l;

           break ;

         case typecode.uint64:

           ulong ul;

           if ( ulong .tryparse(text, out ul)) return ul;

           break ;

         case typecode.single:

           float f;

           if ( float .tryparse(text, out f)) return f;

           break ;

         case typecode. double :

           double d;

           if ( double .tryparse(text, out d)) return d;

           break ;

         case typecode. decimal :

           decimal e;

           if ( decimal .tryparse(text, out e)) return e;

           break ;

       }

       return null ;

     }

     static object parseenum( string name, type type)

     {

       if (type.isenum)

       {

         memberinfo[] memberinfos = type.findmembers(membertypes.field,

           bindingflags. public | bindingflags.declaredonly | bindingflags. static ,

           type.filternameignorecase, name);

         if (memberinfos.length != 0) return ((fieldinfo)memberinfos[0]).getvalue( null );

       }

       return null ;

     }

     static bool iscompatiblewith(type source, type target)

     {

       if (source == target) return true ;

       if (!target.isvaluetype) return target.isassignablefrom(source);

       type st = getnonnullabletype(source);

       type tt = getnonnullabletype(target);

       if (st != source && tt == target) return false ;

       typecode sc = st.isenum ? typecode. object : type.gettypecode(st);

       typecode tc = tt.isenum ? typecode. object : type.gettypecode(tt);

       switch (sc)

       {

         case typecode. sbyte :

           switch (tc)

           {

             case typecode. sbyte :

             case typecode.int16:

             case typecode.int32:

             case typecode.int64:

             case typecode.single:

             case typecode. double :

             case typecode. decimal :

               return true ;

           }

           break ;

         case typecode. byte :

           switch (tc)

           {

             case typecode. byte :

             case typecode.int16:

             case typecode.uint16:

             case typecode.int32:

             case typecode.uint32:

             case typecode.int64:

             case typecode.uint64:

             case typecode.single:

             case typecode. double :

             case typecode. decimal :

               return true ;

           }

           break ;

         case typecode.int16:

           switch (tc)

           {

             case typecode.int16:

             case typecode.int32:

             case typecode.int64:

             case typecode.single:

             case typecode. double :

             case typecode. decimal :

               return true ;

           }

           break ;

         case typecode.uint16:

           switch (tc)

           {

             case typecode.uint16:

             case typecode.int32:

             case typecode.uint32:

             case typecode.int64:

             case typecode.uint64:

             case typecode.single:

             case typecode. double :

             case typecode. decimal :

               return true ;

           }

           break ;

         case typecode.int32:

           switch (tc)

           {

             case typecode.int32:

             case typecode.int64:

             case typecode.single:

             case typecode. double :

             case typecode. decimal :

               return true ;

           }

           break ;

         case typecode.uint32:

           switch (tc)

           {

             case typecode.uint32:

             case typecode.int64:

             case typecode.uint64:

             case typecode.single:

             case typecode. double :

             case typecode. decimal :

               return true ;

           }

           break ;

         case typecode.int64:

           switch (tc)

           {

             case typecode.int64:

             case typecode.single:

             case typecode. double :

             case typecode. decimal :

               return true ;

           }

           break ;

         case typecode.uint64:

           switch (tc)

           {

             case typecode.uint64:

             case typecode.single:

             case typecode. double :

             case typecode. decimal :

               return true ;

           }

           break ;

         case typecode.single:

           switch (tc)

           {

             case typecode.single:

             case typecode. double :

               return true ;

           }

           break ;

         default :

           if (st == tt) return true ;

           break ;

       }

       return false ;

     }

     static bool isbetterthan(expression[] args, methoddata m1, methoddata m2)

     {

       bool better = false ;

       for ( int i = 0; i < args.length; i++)

       {

         int c = compareconversions(args[i].type,

           m1.parameters[i].parametertype,

           m2.parameters[i].parametertype);

         if (c < 0) return false ;

         if (c > 0) better = true ;

       }

       return better;

     }

     // return 1 if s -> t1 is a better conversion than s -> t2

     // return -1 if s -> t2 is a better conversion than s -> t1

     // return 0 if neither conversion is better

     static int compareconversions(type s, type t1, type t2)

     {

       if (t1 == t2) return 0;

       if (s == t1) return 1;

       if (s == t2) return -1;

       bool t1t2 = iscompatiblewith(t1, t2);

       bool t2t1 = iscompatiblewith(t2, t1);

       if (t1t2 && !t2t1) return 1;

       if (t2t1 && !t1t2) return -1;

       if (issignedintegraltype(t1) && isunsignedintegraltype(t2)) return 1;

       if (issignedintegraltype(t2) && isunsignedintegraltype(t1)) return -1;

       return 0;

     }

     expression generateequal(expression left, expression right)

     {

       return expression.equal(left, right);

     }

     expression generatenotequal(expression left, expression right)

     {

       return expression.notequal(left, right);

     }

     expression generategreaterthan(expression left, expression right)

     {

       if (left.type == typeof ( string ))

       {

         return expression.greaterthan(

           generatestaticmethodcall( "compare" , left, right),

           expression.constant(0)

         );

       }

       return expression.greaterthan(left, right);

     }

     expression generategreaterthanequal(expression left, expression right)

     {

       if (left.type == typeof ( string ))

       {

         return expression.greaterthanorequal(

           generatestaticmethodcall( "compare" , left, right),

           expression.constant(0)

         );

       }

       return expression.greaterthanorequal(left, right);

     }

     expression generatelessthan(expression left, expression right)

     {

       if (left.type == typeof ( string ))

       {

         return expression.lessthan(

           generatestaticmethodcall( "compare" , left, right),

           expression.constant(0)

         );

       }

       return expression.lessthan(left, right);

     }

     expression generatelessthanequal(expression left, expression right)

     {

       if (left.type == typeof ( string ))

       {

         return expression.lessthanorequal(

           generatestaticmethodcall( "compare" , left, right),

           expression.constant(0)

         );

       }

       return expression.lessthanorequal(left, right);

     }

     expression generateadd(expression left, expression right)

     {

       if (left.type == typeof ( string ) && right.type == typeof ( string ))

       {

         return generatestaticmethodcall( "concat" , left, right);

       }

       return expression.add(left, right);

     }

     expression generatesubtract(expression left, expression right)

     {

       return expression.subtract(left, right);

     }

     expression generatestringconcat(expression left, expression right)

     {

       return expression.call(

         null ,

         typeof ( string ).getmethod( "concat" , new [] { typeof ( object ), typeof ( object ) }),

         new [] { left, right });

     }

     methodinfo getstaticmethod( string methodname, expression left, expression right)

     {

       return left.type.getmethod(methodname, new [] { left.type, right.type });

     }

     expression generatestaticmethodcall( string methodname, expression left, expression right)

     {

       return expression.call( null , getstaticmethod(methodname, left, right), new [] { left, right });

     }

     void settextpos( int pos)

     {

       textpos = pos;

       ch = textpos < textlen ? text[textpos] : '\0' ;

     }

     void nextchar()

     {

       if (textpos < textlen) textpos++;

       ch = textpos < textlen ? text[textpos] : '\0' ;

     }

     void nexttoken()

     {

       while ( char .iswhitespace(ch)) nextchar();

       tokenid t;

       int tokenpos = textpos;

       switch (ch)

       {

         case '!' :

           nextchar();

           if (ch == '=' )

           {

             nextchar();

             t = tokenid.exclamationequal;

           }

           else

           {

             t = tokenid.exclamation;

           }

           break ;

         case '%' :

           nextchar();

           t = tokenid.percent;

           break ;

         case '&' :

           nextchar();

           if (ch == '&' )

           {

             nextchar();

             t = tokenid.doubleamphersand;

           }

           else

           {

             t = tokenid.amphersand;

           }

           break ;

         case '(' :

           nextchar();

           t = tokenid.openparen;

           break ;

         case ')' :

           nextchar();

           t = tokenid.closeparen;

           break ;

         case '*' :

           nextchar();

           t = tokenid.asterisk;

           break ;

         case '+' :

           nextchar();

           t = tokenid.plus;

           break ;

         case ',' :

           nextchar();

           t = tokenid测试数据ma;

           break ;

         case '-' :

           nextchar();

           t = tokenid.minus;

           break ;

         case '.' :

           nextchar();

           t = tokenid.dot;

           break ;

         case '/' :

           nextchar();

           t = tokenid.slash;

           break ;

         case ':' :

           nextchar();

           t = tokenid.colon;

           break ;

         case '<' :

           nextchar();

           if (ch == '=' )

           {

             nextchar();

             t = tokenid.lessthanequal;

           }

           else if (ch == '>' )

           {

             nextchar();

             t = tokenid.lessgreater;

           }

           else

           {

             t = tokenid.lessthan;

           }

           break ;

         case '=' :

           nextchar();

           if (ch == '=' )

           {

             nextchar();

             t = tokenid.doubleequal;

           }

           else

           {

             t = tokenid.equal;

           }

           break ;

         case '>' :

           nextchar();

           if (ch == '=' )

           {

             nextchar();

             t = tokenid.greaterthanequal;

           }

           else

           {

             t = tokenid.greaterthan;

           }

           break ;

         case '?' :

           nextchar();

           t = tokenid.question;

           break ;

         case '[' :

           nextchar();

           t = tokenid.openbracket;

           break ;

         case ']' :

           nextchar();

           t = tokenid.closebracket;

           break ;

         case '|' :

           nextchar();

           if (ch == '|' )

           {

             nextchar();

             t = tokenid.doublebar;

           }

           else

           {

             t = tokenid.bar;

           }

           break ;

         case '"' :

         case '\'' :

           char quote = ch;

           do

           {

             nextchar();

             while (textpos < textlen && ch != quote) nextchar();

             if (textpos == textlen)

               throw parseerror(textpos, res.unterminatedstringliteral);

             nextchar();

           } while (ch == quote);

           t = tokenid.stringliteral;

           break ;

         default :

           if ( char .isletter(ch) || ch == '@' || ch == '_' )

           {

             do

             {

               nextchar();

             } while ( char .isletterordigit(ch) || ch == '_' );

             t = tokenid.identifier;

             break ;

           }

           if ( char .isdigit(ch))

           {

             t = tokenid.integerliteral;

             do

             {

               nextchar();

             } while ( char .isdigit(ch));

             if (ch == '.' )

             {

               t = tokenid.realliteral;

               nextchar();

               validatedigit();

               do

               {

                 nextchar();

               } while ( char .isdigit(ch));

             }

             if (ch == 'e' || ch == 'e' )

             {

               t = tokenid.realliteral;

               nextchar();

               if (ch == '+' || ch == '-' ) nextchar();

               validatedigit();

               do

               {

                 nextchar();

               } while ( char .isdigit(ch));

             }

             if (ch == 'f' || ch == 'f' ) nextchar();

             break ;

           }

           if (textpos == textlen)

           {

             t = tokenid.end;

             break ;

           }

           throw parseerror(textpos, res.invalidcharacter, ch);

       }

       token.id = t;

       token.text = text.substring(tokenpos, textpos - tokenpos);

       token.pos = tokenpos;

     }

     bool tokenidentifieris( string id)

     {

       return token.id == tokenid.identifier && string .equals(id, token.text, stringcomparison.ordinalignorecase);

     }

     string getidentifier()

     {

       validatetoken(tokenid.identifier, res.identifierexpected);

       string id = token.text;

       if (id.length > 1 && id[0] == '@' ) id = id.substring(1);

       return id;

     }

     void validatedigit()

     {

       if (! char .isdigit(ch)) throw parseerror(textpos, res.digitexpected);

     }

     void validatetoken(tokenid t, string errormessage)

     {

       if (token.id != t) throw parseerror(errormessage);

     }

     void validatetoken(tokenid t)

     {

       if (token.id != t) throw parseerror(res.syntaxerror);

     }

     exception parseerror( string format, params object [] args)

     {

       return parseerror(token.pos, format, args);

     }

     exception parseerror( int pos, string format, params object [] args)

     {

       return new parseexception( string .format(system.globalization.cultureinfo.currentculture, format, args), pos);

     }

     static dictionary< string , object > createkeywords()

     {

       dictionary< string , object > d = new dictionary< string , object >(stringcomparer.ordinalignorecase);

       d.add( "true" , trueliteral);

       d.add( "false" , falseliteral);

       d.add( "null" , nullliteral);

       d.add(keywordit, keywordit);

       d.add(keywordiif, keywordiif);

       d.add(keywordnew, keywordnew);

       foreach (type type in predefinedtypes) d.add(type.name, type);

       return d;

     }

   }

   static class res

   {

     public const string duplicateidentifier = "the identifier '{0}' was defined more than once" ;

     public const string expressiontypemismatch = "expression of type '{0}' expected" ;

     public const string expressionexpected = "expression expected" ;

     public const string invalidcharacterliteral = "character literal must contain exactly one character" ;

     public const string invalidintegerliteral = "invalid integer literal '{0}'" ;

     public const string invalidrealliteral = "invalid real literal '{0}'" ;

     public const string unknownidentifier = "unknown identifier '{0}'" ;

     public const string noitinscope = "no 'it' is in scope" ;

     public const string iifrequiresthreeargs = "the 'iif' function requires three arguments" ;

     public const string firstexprmustbebool = "the first expression must be of type 'boolean'" ;

     public const string bothtypesconverttoother = "both of the types '{0}' and '{1}' convert to the other" ;

     public const string neithertypeconvertstoother = "neither of the types '{0}' and '{1}' converts to the other" ;

     public const string missingasclause = "expression is missing an 'as' clause" ;

     public const string argsincompatiblewithlambda = "argument list incompatible with lambda expression" ;

     public const string typehasnonullableform = "type '{0}' has no nullable form" ;

     public const string nomatchingconstructor = "no matching constructor in type '{0}'" ;

     public const string ambiguousconstructorinvocation = "ambiguous invocation of '{0}' constructor" ;

     public const string cannotconvertvalue = "a value of type '{0}' cannot be converted to type '{1}'" ;

     public const string noapplicablemethod = "no applicable method '{0}' exists in type '{1}'" ;

     public const string methodsareinaccessible = "methods on type '{0}' are not accessible" ;

     public const string methodisvoid = "method '{0}' in type '{1}' does not return a value" ;

     public const string ambiguousmethodinvocation = "ambiguous invocation of method '{0}' in type '{1}'" ;

     public const string unknownpropertyorfield = "no property or field '{0}' exists in type '{1}'" ;

     public const string noapplicableaggregate = "no applicable aggregate method '{0}' exists" ;

     public const string cannotindexmultidimarray = "indexing of multi-dimensional arrays is not supported" ;

     public const string invalidindex = "array index must be an integer expression" ;

     public const string noapplicableindexer = "no applicable indexer exists in type '{0}'" ;

     public const string ambiguousindexerinvocation = "ambiguous invocation of indexer in type '{0}'" ;

     public const string incompatibleoperand = "operator '{0}' incompatible with operand type '{1}'" ;

     public const string incompatibleoperands = "operator '{0}' incompatible with operand types '{1}' and '{2}'" ;

     public const string unterminatedstringliteral = "unterminated string literal" ;

     public const string invalidcharacter = "syntax error '{0}'" ;

     public const string digitexpected = "digit expected" ;

     public const string syntaxerror = "syntax error" ;

     public const string tokenexpected = "{0} expected" ;

     public const string parseexceptionformat = "{0} (at index {1})" ;

     public const string colonexpected = "':' expected" ;

     public const string openparenexpected = "'(' expected" ;

     public const string closeparenoroperatorexpected = "')' or operator expected" ;

     public const string closeparenorcommaexpected = "')' or ',' expected" ;

     public const string dotoropenparenexpected = "'.' or '(' expected" ;

     public const string openbracketexpected = "'[' expected" ;

     public const string closebracketorcommaexpected = "']' or ',' expected" ;

     public const string identifierexpected = "identifier expected" ;

   }

此时,我们需要将我们的实体和数据库字段映射对应起来,新建一个imagemap类代码如下:

?

public class imagemap : entitytypeconfiguration<imagemodel>

   {

     public imagemap()

     {

       // primary key

       this .haskey(t => t.id);

       // properties

       this .property(t => t.idprooffront)

         .hasmaxlength(100);

       this .property(t => t.idproofback)

         .hasmaxlength(100);

       // table & column mappings

       this .totable( "imagemodel" );

       this .property(t => t.id).hascolumnname( "id" );

       this .property(t => t.idprooffront).hascolumnname( "idprooffront" );

       this .property(t => t.idproofback).hascolumnname( "idproofback" );

     }

   }

其中totable就是指明数据库表名,

那么如何将上传的图片保存更新到数据库呢?

接下来我们新建一个接口类iresourcesimage 并继承操作基类 irepository<imagemodel>

定义一个上传身份信息的规则如下:

?

bool updateidproof( string idprooffront, string idproofback, int pid);

接下来我们新建一个resourcesimage 实现上述接口。代码如下:  

?

public resourcesimage() { }

    /// <summary>

    /// 上传身份信息采用此种方式

    /// </summary>

    /// <param name="idproofback"></param>

    /// <param name="idproofback"></param>

    /// <param name="pid"></param>

    /// <returns></returns>

    public bool updateidproof( string idprooffront, string idproofback, int pid)

    {

      int flag = 0;

      if (idprooffront != "" && idprooffront != null )

      {

        flag = this .update(m => m.id == pid, u => new imagemodel { idprooffront = idprooffront });

        if (flag == 1)

        {

          if (idproofback != "" && idproofback != null )

            flag = this .update(m => m.id == pid, u => new imagemodel { idproofback = idproofback });

        }

      }

      else

      {

        if (idproofback != "" && idproofback != null )

          flag = this .update(m => m.id == pid, u => new imagemodel { idproofback = idproofback });

      }

      return flag == 0 ? false : true ;

    }

我们在中间层做一下这个操作:       

?

private readonly iresourcesimage _resourcesimage;

    public codebll()

    {

      this ._resourcesimage = new resourcesimage();

    }

    /// <summary>

    /// 根据字段更新用户的文件资料信息

    /// </summary>

    /// <param name="filenamefield">字段</param>

    /// <param name="filenamevalue">字段值</param>

    /// <param name="pid"></param>

    /// <returns></returns>

    public bool updatefilename( string idprooffront, string idproofback, int pid)

    {

      bool flag = false ;

      flag = _resourcesimage.updateidproof(idprooffront, idproofback, pid);

      return flag;

    }

这样做其实并不科学,需要手动实例化这种仓储操作,科学的方式可以使用ioc(控制反转).

中间层做好之后,我们只需要在homecontroller中调用此方法即可,代码如下:

至此,我们就实现了本地通过ftp方式上传图片代码,并将图片以相对路径保存在数据库中,数据库存放格式如下:

demo下载

git下载

以上所述是小编给大家介绍的c# 中实现ftp 图片上传功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对服务器之家网站的支持!

原文链接:http://HdhCmsTestcnblogs测试数据/zhangxiaoyong/p/7018616.html

dy("nrwz");

查看更多关于C# 中实现ftp 图片上传功能(多快好省)的详细内容...

  阅读:203次