前言

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

效果预览

具体实现

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

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

  1. public class ImageModel:BaseEntity
  2. {
  3. /// <summary>
  4. /// 用户Id
  5. /// </summary>
  6. public int ID { get; set; }
  7. /// <summary>
  8. ///身份证正面相对路径
  9. /// </summary>
  10. public string IDProofFront { get; set; }
  11. /// <summary>
  12. ///身份证背面相对路径
  13. /// </summary>
  14. public string IDProofBack { get; set; }
  15. }

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

  1. public abstract partial class BaseEntity
  2. {
  3.  
  4. public override bool Equals(object obj)
  5. {
  6. return Equals(obj as BaseEntity);
  7. }
  8.  
  9. private Type GetUnproxiedType()
  10. {
  11. return GetType();
  12. }
  13.  
  14. public virtual bool Equals(BaseEntity other)
  15. {
  16. if (other == null)
  17. return false;
  18.  
  19. if (ReferenceEquals(this, other))
  20. return true;
  21. return false;
  22. }
  23.  
  24. public override int GetHashCode()
  25. {
  26. return base.GetHashCode();
  27. }
  28.  
  29. public static bool operator ==(BaseEntity x, BaseEntity y)
  30. {
  31. return Equals(x, y);
  32. }
  33.  
  34. public static bool operator !=(BaseEntity x, BaseEntity y)
  35. {
  36. return !(x == y);
  37. }
  38. }

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

======================回到HTML=======

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

  1. <form enctype="multipart/form-data" id="form" action="/Home/UpLoadImage" method="post">
  2. <div class="full_w" style="margin-top: 100px; margin-left: 30%; width: 800px;">
  3. <div class="h_title">&nbsp;<b>用户上传的文件</b></div>
  4. <div class="entry">
  5. 步骤: <span class="red" style="color: red">(上传资料必须是bmp,gif,jpg,jpeg,png类型,不能大于2M)</span>
  6. <ol>
  7. <li>先按『选择』键选择上传文件;</li>
  8. <li>按『上传』键上传文件;</li>
  9. <li>按『保存』键保存文件;</li>
  10. </ol>
  11. </div>
  12.  
  13. <div class="entry">
  14. <div class="sep"></div>
  15. </div>
  16.  
  17. <div class="entry">
  18. <div id="wrapper" style="text-align: center; position: relative;">
  19. <div class="form-group">
  20. <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;" />
  21.  
  22. </div>
  23. </div>
  24. </div>
  25.  
  26. <table>
  27. <tbody>
  28. <tr>
  29. <td class="entry">身份证正面</td>
  30. <td>
  31.  
  32. @if (Model == null || Model.ID == null || string.IsNullOrEmpty(Model.IDProofFront))
  33. {
  34. <a href="javascript:void(0);" target="_blank" class="winView">
  35. <img style="border: none; width: 150px; height: 100px" src="/img/noupload.png" />
  36. </a>
  37. }
  38. else
  39. {
  40. <a href="@(ViewBag.pathSrc + Model.IDProofFront)" target="_blank"class="winView" >
  41. <img style="border: none; width: 150px; height: 100px" src="@(ViewBag.pathSrc + Model.IDProofFront)" />
  42. </a>
  43. }
  44. @Html.HiddenFor(m => m.IDProofFront)
  45. @Html.HiddenFor(m => m.ID)
  46. </td>
  47. <td>
  48. <a href="javascript:void(0)" class="easyui-linkbutton btnFinleUP" data-op="1" data-type="image">上传</a>
  49. </td>
  50. </tr>
  51. <tr>
  52. <td class="entry">身份证背面</td>
  53. <span id="lblinfosi" style="color: Green"></span>
  54. <td>
  55. @if (Model == null || Model.ID == null || string.IsNullOrEmpty(Model.IDProofBack))
  56. {
  57. <a href="javascript:void(0);" target="_blank" class="winView">
  58. <img style="border: none; width: 150px; height: 100px" src="/img/noupload.png" />
  59. </a>
  60. }
  61. else
  62. {
  63. <a href="@(ViewBag.pathSrc + Model.IDProofBack)" target="_blank" class="winView" >
  64. <img style="border: none; width: 150px; height: 100px" src="@(ViewBag.pathSrc + Model.IDProofBack)" />
  65. </a>
  66. }
  67. @Html.HiddenFor(m => m.IDProofBack)
  68. </td>
  69. <td>
  70. <a href="javascript:void(0)" class="easyui-linkbutton btnFinleUP" data-op="2" data-type="image">上传</a>
  71. </td>
  72. </tr>
  73. </tbody>
  74. </table>
  75.  
  76. <div class="entry">
  77. <button class="button" name="btnSaveAll" value="保存" id="btnSaveAll" style="height: 30px; width: 80px; text-align: center;">保存</button>
  78. <a href="/Home/Index" 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>
  79.  
  80. </div>
  81. </div>
  82. </form>

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

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

  1. /*!
  2. * FileInput Chinese Translations
  3. *
  4. * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
  5. * any HTML markup tags in the messages must not be converted or translated.
  6. *
  7. * @see http://github.com/kartik-v/bootstrap-fileinput
  8. * @author kangqf <kangqingfei@gmail.com>
  9. *
  10. * NOTE: this file must be saved in UTF-8 encoding.
  11. */
  12. (function ($) {
  13. "use strict";
  14.  
  15. $.fn.fileinputLocales['zh'] = {
  16. fileSingle: '文件',
  17. filePlural: '个文件',
  18. browseLabel: '选择 &hellip;',
  19. removeLabel: '移除',
  20. removeTitle: '清除选中文件',
  21. cancelLabel: '取消',
  22. cancelTitle: '取消进行中的上传',
  23. uploadLabel: '上传',
  24. uploadTitle: '上传选中文件',
  25. msgNo: '没有',
  26. msgNoFilesSelected: '',
  27. msgCancelled: '取消',
  28. msgZoomModalHeading: '详细预览',
  29. msgSizeTooSmall: 'File "{name}" (<b>{size} KB</b>) is too small and must be larger than <b>{minSize} KB</b>.',
  30. msgSizeTooLarge: '文件 "{name}" (<b>{size} KB</b>) 超过了允许大小 <b>{maxSize} KB</b>.',
  31. msgFilesTooLess: '你必须选择最少 <b>{n}</b> {files} 来上传. ',
  32. msgFilesTooMany: '选择的上传文件个数 <b>({n})</b> 超出最大文件的限制个数 <b>{m}</b>.',
  33. msgFileNotFound: '文件 "{name}" 未找到!',
  34. msgFileSecured: '安全限制,为了防止读取文件 "{name}".',
  35. msgFileNotReadable: '文件 "{name}" 不可读.',
  36. msgFilePreviewAborted: '取消 "{name}" 的预览.',
  37. msgFilePreviewError: '读取 "{name}" 时出现了一个错误.',
  38. msgInvalidFileName: 'Invalid or unsupported characters in file name "{name}".',
  39. msgInvalidFileType: '不正确的类型 "{name}". 只支持 "{types}" 类型的文件.',
  40. msgInvalidFileExtension: '不正确的文件扩展名 "{name}". 只支持 "{extensions}" 的文件扩展名.',
  41. msgFileTypes: {
  42. 'image': 'image',
  43. 'html': 'HTML',
  44. 'text': 'text',
  45. 'video': 'video',
  46. 'audio': 'audio',
  47. 'flash': 'flash',
  48. 'pdf': 'PDF',
  49. 'object': 'object'
  50. },
  51. msgUploadAborted: '该文件上传被中止',
  52. msgUploadThreshold: 'Processing...',
  53. msgUploadEmpty: 'No valid data available for upload.',
  54. msgValidationError: '验证错误',
  55. msgLoading: '加载第 {index} 文件 共 {files} &hellip;',
  56. msgProgress: '加载第 {index} 文件 共 {files} - {name} - {percent}% 完成.',
  57. msgSelected: '{n} {files} 选中',
  58. msgFoldersNotAllowed: '只支持拖拽文件! 跳过 {n} 拖拽的文件夹.',
  59. msgImageWidthSmall: '宽度的图像文件的"{name}"的必须是至少{size}像素.',
  60. msgImageHeightSmall: '图像文件的"{name}"的高度必须至少为{size}像素.',
  61. msgImageWidthLarge: '宽度的图像文件"{name}"不能超过{size}像素.',
  62. msgImageHeightLarge: '图像文件"{name}"的高度不能超过{size}像素.',
  63. msgImageResizeError: '无法获取的图像尺寸调整。',
  64. msgImageResizeException: '错误而调整图像大小。<pre>{errors}</pre>',
  65. msgAjaxError: 'Something went wrong with the {operation} operation. Please try again later!',
  66. msgAjaxProgressError: '{operation} failed',
  67. ajaxOperations: {
  68. deleteThumb: 'file delete',
  69. uploadThumb: 'single file upload',
  70. uploadBatch: 'batch file upload',
  71. uploadExtra: 'form data upload'
  72. },
  73. dropZoneTitle: '拖拽文件到这里 &hellip;<br>支持多文件同时上传',
  74. dropZoneClickTitle: '<br>(或点击{files}按钮选择文件)',
  75. fileActionSettings: {
  76. removeTitle: '删除文件',
  77. uploadTitle: '上传文件',
  78. zoomTitle: '查看详情',
  79. dragTitle: '移动 / 重置',
  80. indicatorNewTitle: '没有上传',
  81. indicatorSuccessTitle: '上传',
  82. indicatorErrorTitle: '上传错误',
  83. indicatorLoadingTitle: '上传 ...'
  84. },
  85. previewZoomButtonTitles: {
  86. prev: '预览上一个文件',
  87. next: '预览下一个文件',
  88. toggleheader: '缩放',
  89. fullscreen: '全屏',
  90. borderless: '无边界模式',
  91. close: '关闭当前预览'
  92. }
  93. };
  94. })(window.jQuery);

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

  1. //上传控件初始化
  2. function initFileUpload() {
  3. $("#uploadfile").fileinput({
  4. //uploadExtraData: { kvId: '10' },
  5. language: 'zh', //设置语言
  6. showUpload: false, //是否显示上传按钮
  7. uploadAsync: true, //默认异步上传
  8. showRemove: false,
  9. autoReplace: true,
  10. maxFileCount: 1,
  11. maxFileSize: 10240,
  12. dropZoneTitle: '拖拽文件到这里 &hellip;<br>仅限.pdf, .jpg, .jpeg, .gif',
  13. enctype: 'multipart/form-data',
  14. fileActionSettings: { uploadClass: "hidden", zoomClass: "hidden", removeClass: "hidden" },
  15. allowedFileExtensions: ['jpg', 'png', 'gif', 'pdf'],//接收的文件后缀
  16. msgFilesTooMany: "选择上传的文件数量({n}) 超过允许的最大数值{m}!",
  17. uploadUrl: "/FileUpload/FileUpLoad", //上传的地址
  18.  
  19. }).on("filebatchselected", function (event, files) {
  20. $(".file-preview-success").remove();
  21. })
  22.  
  23. $("#uploadfile").on("fileuploaded", function (event, data, previewId, index) {
  24.  
  25. console.log("accountData 初始化后 FileOpt" + accountData);
  26. console.log("accountData.FileOpt " + accountData.FileOpt);
  27. var obj = data.response;
  28. if (obj.Status != 500 && obj.Data != undefined) {
  29. var src = accountData.PathSrc + obj.Data.FileName;
  30. showName = obj.Data.FileName;
  31. //alert(showName);
  32.  
  33. var pId = accountData.PId;
  34. var fileObj = undefined;
  35. var field = "";
  36. var isPdf = false;
  37. debugger;
  38. if (accountData.FileOpt == 1) {
  39. fileObj = $("#IDProofFront");
  40. //$("#PersonInfo_OldIDFile").val(obj.Data.FileName);
  41. field = "IDProofFront";
  42. fileObj.val(obj.Data.FileName);
  43. } else if (accountData.FileOpt == 2) {
  44. fileObj = $("#IDProofBack");
  45. field = "IDProofBack";
  46. $("#IDProofBack").val(showName);
  47. fileObj.val(obj.Data.FileName);
  48. }
  49. //fileObj = $("#IDProofFront");
  50. //$("#IDProofFront").val(obj.Data.FileName);
  51. //field = "IDProofFront";
  52. //fileObj.val(obj.Data.FileName);
  53. fileObj.prev().attr("href", src);
  54. src = isPdf == true ? "/Content/images/PDF.png" : src;
  55. fileObj.prev().find("img").attr("src", src);
  56. } else {
  57. console.error(obj.Data);
  58. }
  59. });
  60.  
  61. $('#uploadfile').on('filesuccessremove', function (event, id) {
  62.  
  63. });
  64. $('#uploadfile').on('fileerror', function (event, data, msg) {
  65.  
  66. });
  67.  
  68. //上传
  69. $(".btnFinleUP").click(function () {
  70. var fileName = $("#uploadfile").val();
  71. var obj = document.getElementById("uploadfile");
  72. var type = $(this).attr("data-op");
  73. //alert("当前点击的type是:" + type);
  74. var fileType = $(this).attr("data-type");
  75. var files = $("#uploadfile").fileinput("getFileStack");
  76.  
  77. if (files.length == 0) {
  78. layer.msg('请选择要上传的文件', function () { });
  79. return;
  80. }
  81. var array = fileType.split(",");
  82. var selectType = files[0].type.toLowerCase();
  83. var falg = false;
  84. for (var i = 0; i < array.length; i++) {
  85. if (selectType.indexOf(array[i]) == -1) {
  86. falg = false;
  87. } else
  88. falg = true;
  89. if (falg)
  90. break;
  91. }
  92. if (!falg) {
  93. layer.msg('只能选择' + fileType + ' 类型的文件', function () { });
  94. return;
  95. }
  96. accountData.FileOpt = type;
  97. $("#uploadfile").fileinput("upload");
  98.  
  99. });
  100. }

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

  1. $(function () {
  2. initFileUpload();
  3. })

FTP上传操作

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

FileUpLoad方法如下

  1. /// <summary>
  2. /// 通过ftp上传指定服务器
  3. /// </summary>
  4. /// <returns></returns>
  5. public ActionResult FileUpLoad()
  6. {
  7.  
  8. bool flag = false;
  9. string msg = string.Empty;
  10. int size = Convert.ToInt16(_fileSize) * * ;
  11.  
  12. try
  13. {
  14. Dictionary<string, string> fileDict = new Dictionary<string, string>();
  15. for (int i = ; i < Request.Files.Count; i++)
  16. {
  17. HttpPostedFileBase file = Request.Files[i];
  18. string extension = Path.GetExtension(file.FileName);
  19. string[] fileExtensions = _fileExtension.Split(';');
  20. if (fileExtensions.Any(o => o.Equals(extension, StringComparison.OrdinalIgnoreCase)))
  21. {
  22. if (file.ContentLength <= size)
  23. {
  24. string fileName = string.Format("{0}_{1}", DateTime.Now.ToString("yyyyMMddHHmmssfff"), Path.GetFileName(file.FileName));
  25. if (file.ContentLength <= * * )
  26. {
  27. byte[] buffer = new byte[file.ContentLength];
  28. file.InputStream.Read(buffer, , file.ContentLength);
  29. flag = FileUpLoad(buffer, file.FileName, out fileName, out msg);
  30. }
  31. else//图片压缩有问题>>
  32. {
  33. var stream = ImageHelper.GetPicThumbnail(file.InputStream, );
  34. byte[] buffer = new byte[stream.Length];
  35. stream.Read(buffer, , (int)stream.Length);
  36. flag = FileUpLoad(buffer, file.FileName, out fileName, out msg);
  37. }
  38. fileDict.Add(Request.Files.AllKeys[i], fileName);
  39. }
  40. else
  41. {
  42. msg = string.Format("上传文件不能大于{0}M", _fileSize);
  43. }
  44. }
  45. else
  46. {
  47. msg = string.Format("上传的文件类型不正确");
  48. }
  49. }
  50. return Json(new { Result = "", MSG = "" + msg, Data = fileDict });
  51.  
  52. }
  53. catch (Exception ex)
  54. {
  55. return Json(new { Result = "", MSG = "网络异常,请稍后再试" });
  56. }
  57. }

其中 _fileExtension _filePath _fileSize 是分别从配置文件中读取出来的如下:

  1. private static string _fileExtension = ConfigurationManager.AppSettings["FileType"];
  2. private readonly string _filePath = ConfigurationManager.AppSettings["UploadPath"];
  3. private readonly string _fileSize = ConfigurationManager.AppSettings["FileSizem"];

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

  1. /// <summary>
  2. /// 上传文件
  3. /// </summary>
  4. /// <param name="fileBytes"></param>
  5. /// <param name="originalName"></param>
  6. /// <param name="msg"></param>
  7. /// <returns></returns>
  8. protected bool FileUpLoad(byte[] fileBytes, string originalName, out string newFileName, out string msg)
  9. {
  10. msg = "";
  11. newFileName = "";
  12. try
  13. {
  14.  
  15. FTPUpFile ftp = new FTPUpFile();
  16. newFileName = ftp.UpFile(fileBytes, originalName);
  17. if (string.IsNullOrEmpty(newFileName))
  18. {
  19. msg = "上传文件时出错!";
  20. return false;
  21. }
  22. return true;
  23. }
  24. catch (Exception ex)
  25. {
  26. msg = ex.Message;
  27. return false;
  28. }
  29. }

其中

  1. FTPUpFile 是一个ftp上传文件帮助类,大家可以直接照搬 ,代码如下:
  1. /// <summary>
  2. /// FTP上传文件
  3. /// </summary>
  4. public class FTPUpFile
  5. {
  6.  
  7. string Filetype = ConfigurationManager.AppSettings["FileType"];
  8. string ipaddress = ConfigurationManager.AppSettings["IPaddress"];
  9. string Username = ConfigurationManager.AppSettings["UserName"];
  10. string Password = ConfigurationManager.AppSettings["Password"];
  11.  
  12. /// <summary>
  13. /// FTP上传文件
  14. /// </summary>
  15. /// <param name="filename">上传文件路径</param>
  16. /// <param name="ftpServerIP">FTP服务器的IP和端口</param>
  17. /// <param name="ftpPath">FTP服务器下的哪个目录</param>
  18. /// <param name="ftpUserID">FTP用户名</param>
  19. /// <param name="ftpPassword">FTP密码</param>
  20. public bool Upload(string filename, string ftpServerIP, string ftpPath, string ftpUserID, string ftpPassword)
  21. {
  22. FileInfo fileInf = new FileInfo(filename);
  23. string uri = "ftp://" + ftpServerIP + "/" + ftpPath + "/" + fileInf.Name;
  24.  
  25. try
  26. {
  27. FtpWebRequest reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri(uri));
  28. // ftp用户名和密码
  29. reqFTP.Credentials = new NetworkCredential(ftpUserID, ftpPassword);
  30. reqFTP.KeepAlive = false;
  31.  
  32. // 指定执行什么命令
  33. reqFTP.Method = WebRequestMethods.Ftp.UploadFile;
  34.  
  35. // 指定数据传输类型
  36. reqFTP.UseBinary = true;
  37.  
  38. // 上传文件时通知服务器文件的大小
  39. reqFTP.ContentLength = fileInf.Length;
  40.  
  41. //this.Invoke(InitUProgress, fileInf.Length);
  42.  
  43. // 缓冲大小设置为2kb
  44. int buffLength = ;
  45.  
  46. byte[] buff = new byte[buffLength];
  47. int contentLen;
  48.  
  49. // 打开一个文件流 (System.IO.FileStream) 去读上传的文件
  50. FileStream fs = fileInf.OpenRead();
  51.  
  52. // 把上传的文件写入流
  53. Stream strm = reqFTP.GetRequestStream();
  54. contentLen = fs.Read(buff, , buffLength);
  55. while (contentLen != )
  56. {
  57. strm.Write(buff, , contentLen);
  58. contentLen = fs.Read(buff, , buffLength);
  59. }
  60.  
  61. // 关闭两个流
  62. strm.Close();
  63. strm.Dispose();
  64. fs.Close();
  65. fs.Dispose();
  66.  
  67. return true;
  68. }
  69. catch (Exception ex)
  70. {
  71.  
  72. return false;
  73. }
  74.  
  75. }
  76.  
  77. /// <summary>
  78. /// 新建目录
  79. /// </summary>
  80. /// <param name="ftpPath"></param>
  81. /// <param name="dirName"></param>
  82. public void MakeDir(string ftpPath, string dirName, string username, string password)
  83. {
  84. try
  85. {
  86.  
  87. //实例化FTP连接
  88. FtpWebRequest request = (FtpWebRequest)FtpWebRequest.Create(new Uri(ftpPath + dirName));
  89.  
  90. // ftp用户名和密码
  91. request.Credentials = new NetworkCredential(username, password);
  92.  
  93. // 默认为true,连接不会被关闭
  94.  
  95. request.KeepAlive = false;
  96.  
  97. //指定FTP操作类型为创建目录
  98. request.Method = WebRequestMethods.Ftp.MakeDirectory;
  99. //获取FTP服务器的响应
  100. FtpWebResponse response = (FtpWebResponse)request.GetResponse();
  101. response.Close();
  102. }
  103. catch (Exception ex)
  104. {
  105. //Respons
  106. }
  107. }
  108.  
  109. /// <summary>
  110. /// 删除指定文件
  111. /// </summary>
  112. /// <param name="ftpPath"></param>
  113. /// <param name="dirName"></param>
  114. /// <param name="username"></param>
  115. /// <param name="password"></param>
  116. public void DeleteFile(string ftpPath, string username, string password)
  117. {
  118. try
  119. {
  120. // string uri = "ftp://" + ftpServerIP + "/" + ftpPath + "/" + fileInf.Name;
  121. //ftpPath = "ftp://192.168.1.111:2005/2012-12-05/20121206O5CATICE.docx";
  122. //password = "111";
  123. //username = "yuanluluoli";
  124. //实例化FTP连接
  125. FtpWebRequest request = (FtpWebRequest)FtpWebRequest.Create(new Uri(ftpPath));
  126. request.Method = WebRequestMethods.Ftp.DeleteFile;
  127. // ftp用户名和密码
  128. request.Credentials = new NetworkCredential(username, password);
  129. // 默认为true,连接不会被关闭
  130. request.KeepAlive = false;
  131. //获取FTP服务器的响应
  132. FtpWebResponse response = (FtpWebResponse)request.GetResponse();
  133. response.Close();
  134. }
  135. catch (Exception ex)
  136. {
  137. //Respons
  138. }
  139. }
  140.  
  141. /// <summary>
  142. /// 检查目录是否存在
  143. /// </summary>
  144. /// <param name="ftpPath">要检查的目录的路径</param>
  145. /// <param name="dirName">要检查的目录名</param>
  146. /// <returns>存在返回true,否则false</returns>
  147. public bool CheckDirectoryExist(string ftpPath, string dirName, string username, string password)
  148. {
  149. bool result = false;
  150. try
  151. {
  152.  
  153. //实例化FTP连接
  154. FtpWebRequest request = (FtpWebRequest)FtpWebRequest.Create(new Uri(ftpPath));
  155. // ftp用户名和密码
  156. request.Credentials = new NetworkCredential(username, password);
  157. request.KeepAlive = false;
  158. //指定FTP操作类型为创建目录
  159. request.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
  160. //获取FTP服务器的响应
  161. FtpWebResponse response = (FtpWebResponse)request.GetResponse();
  162. StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.Default);
  163. StringBuilder str = new StringBuilder();
  164. string line = sr.ReadLine();
  165. while (line != null)
  166. {
  167. str.Append(line);
  168. str.Append("|");
  169. line = sr.ReadLine();
  170. }
  171. string[] datas = str.ToString().Split('|');
  172.  
  173. for (int i = ; i < datas.Length; i++)
  174. {
  175. if (datas[i].Contains("<DIR>"))
  176. {
  177. int index = datas[i].IndexOf("<DIR>");
  178. string name = datas[i].Substring(index + ).Trim();
  179. if (name == dirName)
  180. {
  181. result = true;
  182. break;
  183. }
  184. }
  185. }
  186.  
  187. sr.Close();
  188. sr.Dispose();
  189. response.Close();
  190. }
  191. catch (Exception)
  192. {
  193. return false;
  194. }
  195. return result;
  196. }
  197. /// <summary>
  198. /// 上传文件
  199. /// </summary>
  200. /// <param name="buffer">文件的Byte数组</param>
  201. /// <param name="originalName">文件原始名字(带后缀名)</param>
  202. /// <param name="perStr">新文件名的前缀</param>
  203. /// <returns></returns>
  204. public string UpFile(byte[] buffer, string originalName, string perStr = "")
  205. {
  206. if (buffer == null || buffer.Length <= || string.IsNullOrEmpty(originalName))
  207. throw new ArgumentException("参数错误!");
  208. string filePathstr = string.Empty;
  209. string filepathsql = null;
  210. try
  211. {
  212. string pathstr = perStr + DateTime.Now.ToString().Replace("/", "").Replace("-", "").Replace(":", "").Replace(" ", "");
  213. string rodumlist = GeneralHelper.GetMixPwd();//10位随机数
  214. filePathstr = "~/File/" + pathstr + rodumlist + Path.GetExtension(originalName);
  215. //Stream sr = upfile.PostedFile.InputStream;
  216. //byte[] file = new byte[sr.Length];
  217. //sr.Read(file, 0, file.Length);
  218.  
  219. StreamWriter sw = new StreamWriter(HttpContext.Current.Server.MapPath(filePathstr));
  220. sw.BaseStream.Write(buffer, , buffer.Length);
  221. sw.Flush(); sw.Close();
  222. // file.SaveAs(HttpContext.Current.Server.MapPath(filePathstr));//把文件上传到服务器的绝对路径上
  223.  
  224. bool check;
  225. string ftpPath = DateTime.Now.ToString("yyyy-MM-dd");
  226. string uri = @"ftp://" + ipaddress + "/";
  227. //检查是否存在此目录文件夹
  228. if (CheckDirectoryExist(uri, ftpPath, Username, Password))
  229. {
  230.  
  231. //存在此文件夹就直接上传
  232. check = Upload(HttpContext.Current.Server.MapPath(filePathstr), ipaddress, ftpPath, Username, Password);
  233. }
  234. else
  235. {
  236. MakeDir(uri, ftpPath, Username, Password);//创建
  237. check = Upload(HttpContext.Current.Server.MapPath(filePathstr), ipaddress, ftpPath, Username, Password);
  238. }
  239.  
  240. //成功就更新
  241. if (check)
  242. {
  243.  
  244. filepathsql = ftpPath + "/" + pathstr + rodumlist + Path.GetExtension(originalName);
  245. }
  246.  
  247. //检查是否存在此文件
  248. if (File.Exists(HttpContext.Current.Server.MapPath(filePathstr)))
  249. {
  250. File.Delete(HttpContext.Current.Server.MapPath(filePathstr));
  251. }
  252. return filepathsql;
  253. }
  254. catch (Exception ex)
  255. {
  256. File.Delete(HttpContext.Current.Server.MapPath(filePathstr));
  257. throw ex;
  258. }
  259. }
  260. /// <summary>
  261. /// 上传文件
  262. /// 不修改名字及后缀名
  263. /// </summary>
  264. /// <param name="originalFilePath">上传文件的绝对路径</param>
  265. /// <returns></returns>
  266. public string UpFile(string originalFilePath)
  267. {
  268. if (string.IsNullOrEmpty(originalFilePath))
  269. throw new ArgumentException("参数错误!");
  270. string filepathsql = null;
  271. try
  272. {
  273. //检查是否存在此文件
  274. if (!File.Exists(originalFilePath))
  275. throw new Exception("文件不存在!");
  276.  
  277. //Stream sr = upfile.PostedFile.InputStream;
  278. //byte[] file = new byte[sr.Length];
  279. //sr.Read(file, 0, file.Length);
  280.  
  281. // file.SaveAs(HttpContext.Current.Server.MapPath(filePathstr));//把文件上传到服务器的绝对路径上
  282.  
  283. bool check;
  284. string ftpPath = DateTime.Now.ToString("yyyy-MM-dd");
  285. string uri = @"ftp://" + ipaddress + "/";
  286. //检查是否存在此目录文件夹
  287. if (CheckDirectoryExist(uri, ftpPath, Username, Password))
  288. {
  289. //存在此文件夹就直接上传
  290. check = Upload(originalFilePath, ipaddress, ftpPath, Username, Password);
  291. }
  292. else
  293. {
  294. MakeDir(uri, ftpPath, Username, Password);//创建
  295. check = Upload(originalFilePath, ipaddress, ftpPath, Username, Password);
  296. }
  297. //成功就更新
  298. if (check)
  299. {
  300.  
  301. filepathsql = ftpPath + "/" + Path.GetFileName(originalFilePath);
  302. }
  303. //检查是否存在此文件
  304. if (File.Exists(originalFilePath))
  305. {
  306. File.Delete(originalFilePath);
  307. }
  308. return filepathsql;
  309. }
  310. catch (Exception ex)
  311. {
  312. //File.Delete(originalFilePath);
  313. throw ex;
  314. }
  315. }
  316.  
  317. public string Ftp_Up(HtmlInputFile upfile)
  318. {
  319. //Encrypt En = new Encrypt();
  320.  
  321. string filePathstr = string.Empty;
  322. string filepathsql = null;
  323. try
  324. {
  325. string pathstr = DateTime.Now.ToString().Replace("/", "").Replace("-", "").Replace(":", "").Replace(" ", "");
  326. string rodumlist = GeneralHelper.GetMixPwd();//10位随机数
  327. filePathstr = "~/File/" + pathstr + rodumlist + Path.GetExtension(upfile.PostedFile.FileName);
  328. Stream sr = upfile.PostedFile.InputStream;
  329. byte[] file = new byte[sr.Length];
  330. sr.Read(file, , file.Length);
  331. StreamWriter sw = new StreamWriter(HttpContext.Current.Server.MapPath(filePathstr));
  332. sw.BaseStream.Write(file, , file.Length);
  333. sw.Flush(); sw.Close(); sr.Flush(); sr.Close();
  334. // file.SaveAs(HttpContext.Current.Server.MapPath(filePathstr));//把文件上传到服务器的绝对路径上
  335.  
  336. bool check;
  337. string ftpPath = DateTime.Now.ToString("yyyy-MM-dd");
  338. string uri = @"ftp://" + ipaddress + "/";
  339. //检查是否存在此目录文件夹
  340. if (CheckDirectoryExist(uri, ftpPath, Username, Password))
  341. {
  342.  
  343. //存在此文件夹就直接上传
  344. check = Upload(HttpContext.Current.Server.MapPath(filePathstr), ipaddress, ftpPath, Username, Password);
  345. }
  346. else
  347. {
  348. MakeDir(uri, ftpPath, Username, Password);//创建
  349. check = Upload(HttpContext.Current.Server.MapPath(filePathstr), ipaddress, ftpPath, Username, Password);
  350. }
  351.  
  352. //成功就更新
  353. if (check)
  354. {
  355.  
  356. filepathsql = ftpPath + "/" + pathstr + rodumlist + Path.GetExtension(upfile.PostedFile.FileName);
  357. }
  358.  
  359. //检查是否存在此文件
  360. if (File.Exists(HttpContext.Current.Server.MapPath(filePathstr)))
  361. {
  362. File.Delete(HttpContext.Current.Server.MapPath(filePathstr));
  363. }
  364. return filepathsql;
  365. }
  366. catch (Exception)
  367. {
  368. File.Delete(HttpContext.Current.Server.MapPath(filePathstr));
  369. return filepathsql;
  370. // Response.Write("<script>alert(" + ex.Message + ");</script>");
  371. }
  372. }
  373.  
  374. /// <summary>
  375. /// 上传
  376. /// </summary>
  377. /// <param name="file"></param>
  378. /// <returns></returns>
  379. public string Ftp_Up(HttpPostedFileBase postedFile)
  380. {
  381.  
  382. string filePathstr = string.Empty;
  383. string filepathsql = null;
  384. try
  385. {
  386.  
  387. string pathstr = DateTime.Now.ToString("yyyyMMddHHmmss");
  388. string rodumlist = GeneralHelper.GetMixPwd();//10位随机数
  389. string filename = System.IO.Path.GetFileName(postedFile.FileName);
  390. string eExtension = Path.GetExtension(filename);
  391. string strLocation = HttpContext.Current.Server.MapPath("~/File/");
  392. filePathstr = strLocation + pathstr + rodumlist + eExtension;
  393.  
  394. postedFile.SaveAs(filePathstr);
  395.  
  396. bool check;
  397. string ftpPath = DateTime.Now.ToString("yyyy-MM-dd");
  398. string uri = @"ftp://" + ipaddress + "/";
  399. //检查是否存在此目录文件夹
  400. if (CheckDirectoryExist(uri, ftpPath, Username, Password))
  401. {
  402. //存在此文件夹就直接上传
  403. check = Upload(filePathstr, ipaddress, ftpPath, Username, Password);
  404. }
  405. else
  406. {
  407. MakeDir(uri, ftpPath, Username, Password);//创建
  408. check = Upload(filePathstr, ipaddress, ftpPath, Username, Password);
  409. }
  410.  
  411. //成功就更新
  412. if (check)
  413. {
  414.  
  415. filepathsql = ftpPath + "/" + pathstr + rodumlist + eExtension;
  416. }
  417.  
  418. //检查是否存在此文件
  419. if (File.Exists(filePathstr))
  420. {
  421. File.Delete(filePathstr);
  422. }
  423. return filepathsql;
  424. }
  425. catch (Exception ex)
  426. {
  427. //检查是否存在此文件
  428. if (File.Exists(filePathstr))
  429. {
  430. File.Delete(filePathstr);
  431. }
  432. return "";
  433. // Response.Write("<script>alert(" + ex.Message + ");</script>");
  434. }
  435. }
  436.  
  437. /// <summary>
  438. /// FTP下载文件在服务器目录
  439. /// </summary>
  440. /// <param name="pathname">本地保存目录路径和文件名称</param>
  441. /// <param name="filename">FTP目录路径和文件名称</param>
  442. /// <returns></returns>
  443. public bool FileDown(string pathname, string filename)
  444. {
  445. string uri = "ftp://" + ipaddress + "/" + filename;
  446. string FileName = pathname;//本地保存目录
  447.  
  448. //创建一个文件流
  449. FileStream fs = null;
  450. Stream responseStream = null;
  451. try
  452. {
  453. //创建一个与FTP服务器联系的FtpWebRequest对象
  454. FtpWebRequest request = (FtpWebRequest)WebRequest.Create(new Uri(uri));
  455.  
  456. //连接登录FTP服务器
  457. request.Credentials = new NetworkCredential(Username, Password);
  458.  
  459. request.KeepAlive = false;
  460.  
  461. //设置请求的方法是FTP文件下载
  462. request.Method = WebRequestMethods.Ftp.DownloadFile;
  463.  
  464. //获取一个请求响应对象
  465. FtpWebResponse response = (FtpWebResponse)request.GetResponse();
  466. //获取请求的响应流
  467. responseStream = response.GetResponseStream();
  468.  
  469. //判断本地文件是否存在,如果存在,则打开和重写本地文件
  470.  
  471. if (File.Exists(FileName))
  472. fs = File.Open(FileName, FileMode.Open, FileAccess.ReadWrite);
  473.  
  474. //判断本地文件是否存在,如果不存在,则创建本地文件
  475. else
  476. {
  477. fs = File.Create(FileName);
  478. }
  479.  
  480. if (fs != null)
  481. {
  482.  
  483. int buffer_count = ;
  484. byte[] buffer = new byte[buffer_count];
  485. int size = ;
  486. while ((size = responseStream.Read(buffer, , buffer_count)) > )
  487. {
  488. fs.Write(buffer, , size);
  489.  
  490. }
  491. fs.Flush();
  492. fs.Close();
  493. responseStream.Close();
  494. }
  495.  
  496. return true;
  497. }
  498. catch (Exception ex)
  499. {
  500. return false;
  501. }
  502. finally
  503. {
  504. if (fs != null)
  505. fs.Close();
  506. if (responseStream != null)
  507. responseStream.Close();
  508. }
  509. }
  510.  
  511. /// <summary>
  512. /// 保存和上传图片
  513. /// </summary>
  514. /// <param name="imgtwo">需要上传图片</param>
  515. /// <param name="date"></param>
  516. /// <returns>文件路径</returns>
  517. public string SaveUploadImg(Bitmap imgtwo)
  518. {
  519. string filePathstr = string.Empty;
  520. string filepathsql = null;
  521. try
  522. {
  523. string pathstr = DateTime.Now.ToString().Replace("/", "").Replace("-", "").Replace(":", "").Replace(" ", "");
  524. string rodumlist = GeneralHelper.GetMixPwd();//10位随机数
  525. filePathstr = "~/File/" + pathstr + rodumlist + ".jpg";
  526. imgtwo.Save(HttpContext.Current.Server.MapPath(filePathstr));//把文件上传到服务器的绝对路径上
  527.  
  528. bool check;
  529. string ftpPath = DateTime.Now.ToString("yyyy-MM-dd");
  530. string uri = @"ftp://" + ipaddress + "/";
  531. //检查是否存在此目录文件夹
  532. if (CheckDirectoryExist(uri, ftpPath, Username, Password))
  533. {
  534. //存在此文件夹就直接上传
  535. check = Upload(HttpContext.Current.Server.MapPath(filePathstr), ipaddress, ftpPath, Username, Password);
  536. }
  537. else
  538. {
  539. MakeDir(uri, ftpPath, Username, Password);//创建
  540. check = Upload(HttpContext.Current.Server.MapPath(filePathstr), ipaddress, ftpPath, Username, Password);
  541. }
  542.  
  543. //成功就更新
  544. if (check)
  545. {
  546. filepathsql = ftpPath + "/" + pathstr + rodumlist + ".jpg";
  547. }
  548.  
  549. //检查是否存在此文件
  550. if (File.Exists(HttpContext.Current.Server.MapPath(filePathstr)))
  551. {
  552. File.Delete(HttpContext.Current.Server.MapPath(filePathstr));
  553. }
  554. imgtwo.Dispose();
  555.  
  556. return filepathsql;
  557. }
  558. catch (Exception ex)
  559. {
  560. File.Delete(HttpContext.Current.Server.MapPath(filePathstr));
  561. return filepathsql;
  562. }
  563. }
  564.  
  565. #region
  566. /// <summary>
  567. /// 文件大小
  568. /// </summary>
  569. public bool _File_Length(int ContentLength)
  570. {
  571. bool length = false;
  572. int FileLen = ContentLength;
  573. if (FileLen > * == false)//不能超过2M
  574. {
  575. length = true;
  576. }
  577. return length;
  578. }
  579. #endregion
  580.  
  581. //用来获取文件类型
  582. public bool File_PastFileName(string fileName)
  583. {
  584. //bmp, doc, docx, gif, jpg, jpeg, pdf, png, tif, tiff
  585. bool isnot = true;
  586. string ext = Path.GetExtension(fileName);
  587. string[] type = Filetype.Split(';');
  588. for (int i = ; i < type.Length; i++)
  589. {
  590. if (type[i].ToLower() == ext.ToLower())
  591. {
  592. isnot = false;
  593. break;
  594. }
  595. }
  596. return isnot;
  597.  
  598. }
  599.  
  600. }

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

  1. <add key="FileSizem" value="10"></add>
  2. <add key="FileType" value=".bmp;.gif;.jpg;.jpeg;.png;.pdf" />
  3. <!---本地测试-->
  4. <add key="IPaddress" value="路径" />
  5. <!--FTP上传文件的帐号-->
  6. <add key="UserName" value="账号" />
  7. <!--FTP上传文件的密码-->
  8. <add key="Password" value="密码" />
  9. <!--后台显示图片地址-->
  10. <add key="PathSrc" value="路径" />

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

  1. public class ImageHelper
  2. {
  3. /// <summary>
  4. /// 图片压缩
  5. /// </summary>
  6. /// <param name="sFile">原图路径</param>
  7. /// <param name="dFile">保存路径</param>
  8. /// <param name="flag">压缩质量(数字越小压缩率越高) 1-100</param>
  9. /// <param name="dWidth">宽度</param>
  10. /// <param name="dHeight">高度</param>
  11. /// <returns></returns>
  12. public static bool SavePicThumbnail(string sFile, string dFile, int flag, int dWidth = , int dHeight = )
  13. {
  14.  
  15. System.Drawing.Image iSource = System.Drawing.Image.FromFile(sFile);
  16. return SavePicThumbnail(dFile, flag, iSource, dWidth, dHeight);
  17.  
  18. }
  19. /// <summary>
  20. /// 图片压缩
  21. /// </summary>
  22. /// <param name="sFile">原图流</param>
  23. /// <param name="dFile">保存路径</param>
  24. /// <param name="flag">压缩质量(数字越小压缩率越高) 1-100</param>
  25. /// <param name="dWidth">宽度</param>
  26. /// <param name="dHeight">高度</param>
  27. /// <returns></returns>
  28. public static bool SavePicThumbnail(Stream stream, string dFile, int flag, int dWidth = , int dHeight = )
  29. {
  30.  
  31. System.Drawing.Image iSource = System.Drawing.Image.FromStream(stream);
  32. return SavePicThumbnail(dFile, flag, iSource, dWidth, dHeight);
  33.  
  34. }
  35.  
  36. #region GetPicThumbnail
  37.  
  38. public static Stream GetPicThumbnail(Stream stream ,int flag, int dWidth = , int dHeight = )
  39. {
  40. System.Drawing.Image iSource = System.Drawing.Image.FromStream(stream);
  41. ImageFormat tFormat = iSource.RawFormat;
  42. int sW = , sH = ;
  43. if (dHeight == && dWidth == )
  44. {
  45. sW = iSource.Width;
  46. sH = iSource.Height;
  47. }
  48. else if (dWidth != )
  49. {
  50. sW = dWidth;
  51. sH = iSource.Height * dWidth / iSource.Width;
  52. }
  53. else if (dHeight != )
  54. {
  55. sH = dHeight;
  56. sW = iSource.Width * dHeight / iSource.Height;
  57. }
  58. Bitmap ob = new Bitmap(sW, sH);
  59. Graphics g = Graphics.FromImage(ob);
  60. g.Clear(Color.WhiteSmoke);
  61. g.CompositingQuality = CompositingQuality.HighQuality;
  62. g.SmoothingMode = SmoothingMode.HighQuality;
  63. g.InterpolationMode = InterpolationMode.HighQualityBicubic;
  64. g.DrawImage(iSource, new Rectangle(, , sW, sH), , , iSource.Width, iSource.Height, GraphicsUnit.Pixel);
  65. g.Dispose();
  66. //以下代码为保存图片时,设置压缩质量
  67. EncoderParameters ep = new EncoderParameters();
  68. long[] qy = new long[];
  69. qy[] = flag;//设置压缩的比例1-100
  70. EncoderParameter eParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, qy);
  71. ep.Param[] = eParam;
  72. MemoryStream ms = new MemoryStream();
  73. try
  74. {
  75. ImageCodecInfo[] arrayICI = ImageCodecInfo.GetImageEncoders();
  76. ImageCodecInfo jpegICIinfo = null;
  77. for (int x = ; x < arrayICI.Length; x++)
  78. {
  79. if (arrayICI[x].FormatDescription.Equals("JPEG"))
  80. {
  81. jpegICIinfo = arrayICI[x];
  82. break;
  83. }
  84. }
  85. if (jpegICIinfo != null)
  86. {
  87. ob.Save(ms, jpegICIinfo, ep);//dFile是压缩后的新路径
  88.  
  89. }
  90. else
  91. {
  92. ob.Save(ms, tFormat);
  93. }
  94.  
  95. return stream;
  96. }
  97. catch
  98. {
  99. return null;
  100. }
  101. finally
  102. {
  103. iSource.Dispose();
  104. ob.Dispose();
  105. }
  106. }
  107.  
  108. public static bool SavePicThumbnail(string dFile, int flag, System.Drawing.Image iSource, int dWidth = , int dHeight = )
  109. {
  110.  
  111. ImageFormat tFormat = iSource.RawFormat;
  112. int sW = , sH = ;
  113. if (dHeight == && dWidth == )
  114. {
  115. sW = iSource.Width;
  116. sH = iSource.Height;
  117. }
  118. else if (dWidth != )
  119. {
  120. sW = dWidth;
  121. sH = iSource.Height * dWidth / iSource.Width;
  122. }
  123. else if (dHeight != )
  124. {
  125. sH = dHeight;
  126. sW = iSource.Width * dHeight / iSource.Height;
  127. }
  128. Bitmap ob = new Bitmap(sW, sH);
  129. Graphics g = Graphics.FromImage(ob);
  130. g.Clear(Color.WhiteSmoke);
  131. g.CompositingQuality = CompositingQuality.HighQuality;
  132. g.SmoothingMode = SmoothingMode.HighQuality;
  133. g.InterpolationMode = InterpolationMode.HighQualityBicubic;
  134. g.DrawImage(iSource, new Rectangle(, , sW, sH), , , iSource.Width, iSource.Height, GraphicsUnit.Pixel);
  135. g.Dispose();
  136. //以下代码为保存图片时,设置压缩质量
  137. EncoderParameters ep = new EncoderParameters();
  138. long[] qy = new long[];
  139. qy[] = flag;//设置压缩的比例1-100
  140. EncoderParameter eParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, qy);
  141. ep.Param[] = eParam;
  142. try
  143. {
  144. ImageCodecInfo[] arrayICI = ImageCodecInfo.GetImageEncoders();
  145. ImageCodecInfo jpegICIinfo = null;
  146. for (int x = ; x < arrayICI.Length; x++)
  147. {
  148. if (arrayICI[x].FormatDescription.Equals("JPEG"))
  149. {
  150. jpegICIinfo = arrayICI[x];
  151. break;
  152. }
  153. }
  154. if (jpegICIinfo != null)
  155. {
  156. ob.Save(dFile, jpegICIinfo, ep);//dFile是压缩后的新路径
  157. }
  158. else
  159. {
  160. ob.Save(dFile, tFormat);
  161. }
  162. return true;
  163. }
  164. catch
  165. {
  166. return false;
  167. }
  168. finally
  169. {
  170. iSource.Dispose();
  171. ob.Dispose();
  172. }
  173. }
  174. #endregion
  175. }

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

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

保存图片

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

  1. public interface IRepository<T> where T : BaseEntity
  2. {
  3.  
  4. /// <summary>
  5. /// 根据过滤条件,获取记录
  6. /// </summary>
  7. /// <param name="exp"></param>
  8. /// <param name="isNoTracking">(默认不跟踪实体状态)使用NoTracking的查询会在性能方面得到改善</param>
  9. /// <returns></returns>
  10. IQueryable<T> Find(Expression<Func<T, bool>> exp = null, bool isNoTracking = true);
  11.  
  12. /// <summary>
  13. /// 根据过滤条件,获取记录
  14. /// </summary>
  15. /// <param name="whereLambda"></param>
  16. /// <param name="isNoTracking">(默认不跟踪实体状态)使用NoTracking的查询会在性能方面得到改善</param>
  17. /// <param name="values"></param>
  18. /// <returns></returns>
  19. IQueryable<T> Find(string whereLambda = null, bool isNoTracking = true, params object[] values);
  20.  
  21. IQueryable<TEntity> OtherTable<TEntity>() where TEntity : BaseEntity;
  22. IDbSet<TEntity> Set<TEntity>() where TEntity : BaseEntity;
  23. /// <summary>
  24. /// 判断记录是否存在
  25. /// </summary>
  26. /// <param name="exp"></param>
  27. /// <returns></returns>
  28. bool IsExist(Expression<Func<T, bool>> exp);
  29. /// <summary>
  30. /// 查找单个(如果没找到则返回为NULL)
  31. /// </summary>
  32. /// <param name="exp"></param>
  33. /// <param name="isNoTracking">(默认不跟踪实体状态)使用NoTracking的查询会在性能方面得到改善</param>
  34. /// <returns></returns>
  35. T FindSingle(Expression<Func<T, bool>> exp, bool isNoTracking = true);
  36.  
  37. /// <summary>
  38. /// 得到分页记录
  39. /// </summary>
  40. /// <param name="pageIndex">The pageindex.</param>
  41. /// <param name="pageSize">The pagesize.</param>
  42. /// <param name="total">总条数</param>
  43. /// <param name="exp">条件谓词</param>
  44. /// <param name="orderBy">排序,格式如:"Id"/"Id descending"</param>
  45. IQueryable<T> Find(int pageIndex, int pageSize, out int total, Expression<Func<T, bool>> exp = null, string orderBy = "");
  46.  
  47. /// <summary>
  48. /// 得到分页记录
  49. /// </summary>
  50. /// <param name="pageIndex">The pageindex.</param>
  51. /// <param name="pageSize">The pagesize.</param>
  52. /// <param name="total">总条数</param>
  53. /// <param name="whereLambda">条件谓词</param>
  54. /// <param name="orderBy">排序,格式如:"Id"/"Id descending"</param>
  55. IQueryable<T> Find(int pageIndex, int pageSize, out int total, string whereLambda = "", string orderBy = "", params object[] values);
  56.  
  57. /// <summary>
  58. /// 根据过滤条件获取记录数
  59. /// </summary>
  60. int GetCount(Expression<Func<T, bool>> exp = null);
  61.  
  62. /// <summary>
  63. /// 添加实体
  64. /// </summary>
  65. /// <param name="entity">The entities.</param>
  66. /// <param name="isComit">是否提交(true)</param>
  67. /// <returns></returns>
  68. int Add(T entity, bool isComit = true);
  69. /// <summary>
  70. /// 批量添加
  71. /// </summary>
  72. /// <param name="entity">The entities.</param>
  73. /// <param name="isComit">是否提交(true)</param>
  74. int Adds(List<T> entitis, bool isComit = true);
  75. /// <summary>
  76. /// 更新实体(会更新实体的所有属性)
  77. /// </summary>
  78. /// <param name="entity">The entities.</param>
  79. /// <param name="isComit">是否提交(true)</param>
  80. /// <returns></returns>
  81. int Update(T entity, bool isComit = true);
  82. /// <summary>
  83. /// 删除实体
  84. /// </summary>
  85. /// <param name="entity">The entities.</param>
  86. /// <param name="isComit">是否提交(true)</param>
  87. /// <returns></returns>
  88. int Delete(T entity, bool isComit = true);
  89.  
  90. /// <summary>
  91. /// 实现按需要只更新部分更新
  92. /// <para>如:Update(u =>u.Id==1,u =>new User{Name="ok"});</para>
  93. /// </summary>
  94. /// <param name="where">The where.</param>
  95. /// <param name="entity">The entity.</param>
  96. int Update(Expression<Func<T, bool>> where, Expression<Func<T, T>> entity);
  97. /// <summary>
  98. /// 批量按条件删除
  99. /// </summary>
  100. /// <param name="exp"></param>
  101. int Delete(Expression<Func<T, bool>> exp);
  102.  
  103. /// <summary>
  104. /// 对数据库执行给定的 DDL/DML 命令。
  105. /// </summary>
  106. /// <param name="sql">sql</param>
  107. /// <param name="parameters">参数</param>
  108. /// <returns></returns>
  109. int ExecuteSqlCommand(string sql, params SqlParameter[] parameters);
  110. /// <summary>
  111. /// 执行SQL查询语句
  112. /// </summary>
  113. /// <param name="sql"></param>
  114. /// <returns></returns>
  115. DbRawSqlQuery<int> ExecuteSqlQuery(string sql);
  116.  
  117. /// <summary>
  118. /// 执行原始的sql查询
  119. /// </summary>
  120. /// <typeparam name="TElement">返回的泛型类型</typeparam>
  121. /// <param name="sql">sql</param>
  122. /// <param name="parameters">参数</param>
  123. /// <returns></returns>
  124. IList<TElement> SqlQuery<TElement>(string sql, params SqlParameter[] parameters);
  125.  
  126. /// <summary>
  127. /// 开启一个事务
  128. /// </summary>
  129. /// <param name="fun"></param>
  130. bool BeginTransaction(Func<bool> fun);
  131.  
  132. /// <summary>
  133. /// 执行SQL语句或存储过程
  134. /// 返回Datatable数据集
  135. /// </summary>
  136. /// <param name="sql">SQL语句或存储过程 例如:exec usp_procedure</param>
  137. /// <param name="parameters">参数列表</param>
  138. /// <returns></returns>
  139. DataTable SqlQueryForDataTable(string sql, DbParameter[] parameters);
  140.  
  141. /// <summary>
  142. /// 返回Datatable数据集
  143. /// </summary>
  144. /// <param name="proName">存储过程名</param>
  145. /// <param name="parameters">参数列表</param>
  146. /// <returns></returns>
  147. [Obsolete("此方法已过时,请改用SqlQueryForDataTable")]
  148. DataTable ExecuteForDataTable(string proName, IDataParameter[] parameters);
  149. }

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

  1. public class BaseRepository<T> : IRepository<T> where T : BaseEntity
  2. {
  3.  
  4. private DbContext Context
  5. {
  6. get
  7. {
  8. DbContext db = (DbContext)CallContext.GetData("DbContext");
  9. if (db == null)
  10. {
  11. db = new DbContext();
  12. // db.Database.Log = o => LoggingHelper.Instance.Logging(LogLevel.Debug, o);
  13. CallContext.SetData("DbContext", db);
  14. }
  15. return db;
  16. }
  17. }
  18.  
  19. /// <summary>
  20. /// 根据过滤条件,获取记录
  21. /// </summary>
  22. /// <param name="exp"></param>
  23. /// <param name="isNoTracking">(默认不跟踪实体状态)使用NoTracking的查询会在性能方面得到改善</param>
  24. /// <returns></returns>
  25. public IQueryable<T> Find(Expression<Func<T, bool>> exp = null, bool isNoTracking = true)
  26. {
  27. return Filter(exp, isNoTracking);
  28. }
  29.  
  30. /// <summary>
  31. /// 根据过滤条件,获取记录
  32. /// </summary>
  33. /// <param name="whereLambda"></param>
  34. /// <param name="isNoTracking">(默认不跟踪实体状态)使用NoTracking的查询会在性能方面得到改善</param>
  35. /// <param name="values"></param>
  36. /// <returns></returns>
  37. public IQueryable<T> Find(string whereLambda = null, bool isNoTracking = true, params object[] values)
  38. {
  39. return Filter(whereLambda, isNoTracking, values);
  40. }
  41.  
  42. /// <summary>
  43. /// 判断记录是否存在
  44. /// </summary>
  45. /// <param name="exp"></param>
  46. /// <returns></returns>
  47. public bool IsExist(Expression<Func<T, bool>> exp)
  48. {
  49. return Context.Set<T>().Any(exp);
  50. }
  51.  
  52. /// <summary>
  53. /// 查找单个(如果没找到则返回为NULL)
  54. /// </summary>
  55. /// <param name="exp"></param>
  56. /// <param name="isNoTracking">(默认不跟踪实体状态)使用NoTracking的查询会在性能方面得到改善</param>
  57. /// <returns></returns>
  58. public T FindSingle(Expression<Func<T, bool>> exp, bool isNoTracking = true)
  59. {
  60. return Filter(exp, isNoTracking).FirstOrDefault();
  61. }
  62.  
  63. /// <summary>
  64. /// 得到分页记录
  65. /// </summary>
  66. /// <param name="pageIndex">The pageindex.</param>
  67. /// <param name="pageSize">The pagesize.</param>
  68. /// <param name="total">总条数</param>
  69. /// <param name="exp">条件谓词</param>
  70. /// <param name="orderBy">排序,格式如:"Id"/"Id descending"</param>
  71. public IQueryable<T> Find(int pageIndex, int pageSize, out int total, Expression<Func<T, bool>> exp = null, string orderBy = "")
  72. {
  73. if (pageIndex < ) pageIndex = ;
  74. var query = Filter(exp);
  75. if (!string.IsNullOrEmpty(orderBy))
  76. query = query.OrderBy(orderBy);
  77. total = query.Count();
  78. ///return query.Skip(pageSize * (pageIndex - 1)).Take(pageSize);
  79. return null;
  80. }
  81.  
  82. /// <summary>
  83. /// 得到分页记录
  84. /// </summary>
  85. /// <param name="pageIndex">The pageindex.</param>
  86. /// <param name="pageSize">The pagesize.</param>
  87. /// <param name="total">总条数</param>
  88. /// <param name="whereLambda">条件谓词</param>
  89. /// <param name="orderBy">排序,格式如:"Id"/"Id descending"</param>
  90. public IQueryable<T> Find(int pageIndex, int pageSize, out int total, string whereLambda = "", string orderBy = "", params object[] values)
  91. {
  92. if (pageIndex < ) pageIndex = ;
  93. var query = Filter(whereLambda);
  94. if (string.IsNullOrEmpty(orderBy))
  95. query = query.OrderBy(orderBy);
  96. total = query.Count();
  97. // return query.Skip(pageSize * (pageIndex - 1)).Take(pageSize);
  98. return null;
  99. }
  100.  
  101. /// <summary>
  102. /// 根据过滤条件获取记录数
  103. /// </summary>
  104. public int GetCount(Expression<Func<T, bool>> exp = null)
  105. {
  106. return Filter(exp).Count();
  107. }
  108.  
  109. /// <summary>
  110. /// 添加书体
  111. /// </summary>
  112. /// <param name="entity">The entities.</param>
  113. /// <param name="isComit">是否提交(true)</param>
  114. /// <returns></returns>
  115. public int Add(T entity, bool isComit = true)
  116. {
  117.  
  118. Context.Entry<T>(entity).State = System.Data.Entity.EntityState.Added;
  119. return isComit ? Context.SaveChanges() : ;
  120. }
  121.  
  122. /// <summary>
  123. /// 批量添加
  124. /// </summary>
  125. /// <param name="entity">The entities.</param>
  126. /// <param name="isComit">是否提交(true)</param>
  127. public int Adds(List<T> entitis, bool isComit = true)
  128. {
  129. foreach (T item in entitis)
  130. {
  131. Context.Entry<T>(item).State = System.Data.Entity.EntityState.Added;
  132. }
  133. return isComit ? Context.SaveChanges() : ;
  134. }
  135. /// <summary>
  136. /// 更新实体(会更新实体的所有属性)
  137. /// </summary>
  138. /// <param name="entity">The entities.</param>
  139. /// <param name="isComit">是否提交(true)</param>
  140. /// <returns></returns>
  141. public int Update(T entity, bool isComit = true)
  142. {
  143. Context.Entry(entity).State = System.Data.Entity.EntityState.Modified;
  144. return isComit ? Context.SaveChanges() : ;
  145. }
  146. /// <summary>
  147. /// 删除实体
  148. /// </summary>
  149. /// <param name="entity">The entities.</param>
  150. /// <param name="isComit">是否提交(true)</param>
  151. /// <returns></returns>
  152. public int Delete(T entity, bool isComit = true)
  153. {
  154. Context.Set<T>().Remove(entity);
  155. return isComit ? Context.SaveChanges() : ;
  156. }
  157.  
  158. /// <summary>
  159. /// 实现按需要只更新部分更新
  160. /// <para>如:Update(u =>u.Id==1,u =>new User{Name="ok"});</para>
  161. /// </summary>
  162. /// <param name="where">The where.</param>
  163. /// <param name="entity">The entity.</param>
  164. public int Update(Expression<Func<T, bool>> where, Expression<Func<T, T>> entity)
  165. {
  166. return Context.Set<T>().Where(where).Update(entity);
  167. }
  168.  
  169. /// <summary>
  170. /// 批量按条件删除
  171. /// </summary>
  172. /// <param name="exp"></param>
  173. public int Delete(Expression<Func<T, bool>> exp)
  174. {
  175. return Context.Set<T>().Where(exp).Delete();
  176. }
  177.  
  178. /// <summary>
  179. /// 对数据库执行给定的 DDL/DML 命令。
  180. /// </summary>
  181. /// <param name="sql">sql</param>
  182. /// <param name="parameters">参数</param>
  183. /// <returns></returns>
  184. public int ExecuteSqlCommand(string sql, params SqlParameter[] parameters)
  185. {
  186. return Context.Database.ExecuteSqlCommand(sql, parameters);
  187. }
  188.  
  189. /// <summary>
  190. /// 执行原始的sql查询
  191. /// </summary>
  192. /// <typeparam name="TElement">返回的泛型类型</typeparam>
  193. /// <param name="sql">sql</param>
  194. /// <param name="parameters">参数</param>
  195. /// <returns></returns>
  196. public IList<TElement> SqlQuery<TElement>(string sql, params SqlParameter[] parameters)
  197. {
  198. return Context.Database.SqlQuery<TElement>(sql, parameters).ToList();
  199. }
  200.  
  201. public bool BeginTransaction(Func<bool> fun)
  202. {
  203. using (var trans = Context.Database.BeginTransaction())
  204. {
  205. try
  206. {
  207. var result = fun();
  208. trans.Commit();
  209. return result;
  210. }
  211. catch (Exception)
  212. {
  213. trans.Rollback();
  214. return false;
  215. }
  216.  
  217. }
  218. }
  219.  
  220. private IQueryable<T> Filter(Expression<Func<T, bool>> exp = null, bool isNoTracking = true)
  221. {
  222. var dbSet = Context.Set<T>().AsQueryable();
  223. if (exp != null)
  224. dbSet = dbSet.Where(exp);
  225. if (isNoTracking)
  226. dbSet = dbSet.AsNoTracking();
  227. return dbSet;
  228. }
  229.  
  230. private IQueryable<T> Filter(string whereLambda = null, bool isNoTracking = true, params object[] values)
  231. {
  232. var dbSet = Context.Set<T>().AsQueryable();
  233. if (whereLambda != null)
  234. dbSet = dbSet.Where(whereLambda, values);
  235. if (isNoTracking)
  236. dbSet = dbSet.AsNoTracking();
  237. return dbSet;
  238. }
  239. public IQueryable<T> Table
  240. {
  241. get
  242. {
  243. return Find(whereLambda: null);
  244. }
  245. }
  246.  
  247. public IQueryable<TEntity> OtherTable<TEntity>() where TEntity : BaseEntity
  248. {
  249. return Context.Set<TEntity>().AsNoTracking().AsQueryable();
  250. }
  251. public IDbSet<TEntity> Set<TEntity>() where TEntity : BaseEntity
  252. {
  253. return Context.Set<TEntity>();
  254. }
  255.  
  256. /// <summary>
  257. /// 执行SQL查询语句
  258. /// </summary>
  259. /// <param name="sql"></param>
  260. /// <returns></returns>
  261. public DbRawSqlQuery<int> ExecuteSqlQuery(string sql)
  262. {
  263. try
  264. {
  265. return Context.Database.SqlQuery<int>(sql);
  266. }
  267. catch (Exception ex)
  268. {
  269. throw ex;
  270. }
  271. }
  272.  
  273. /// <summary>
  274. /// 执行SQL语句或存储过程
  275. /// 返回Datatable数据集
  276. /// </summary>
  277. /// <param name="sql">SQL语句或存储过程 例如:exec usp_procedure</param>
  278. /// <param name="parameters">参数列表</param>
  279. /// <returns></returns>
  280. public System.Data.DataTable SqlQueryForDataTable(string sql, params System.Data.Common.DbParameter[] parameters)
  281. {
  282. SqlConnection conn = new System.Data.SqlClient.SqlConnection();
  283. try
  284. {
  285. conn = (SqlConnection)Context.Database.Connection;
  286. if (conn.State != ConnectionState.Open)
  287. {
  288. conn.Open();
  289. }
  290. SqlCommand cmd = new SqlCommand();
  291. StringBuilder sb = new StringBuilder(sql);
  292. if (parameters != null && parameters.Length > )
  293. {
  294. if (sql.StartsWith("exec ", StringComparison.OrdinalIgnoreCase))
  295. sb.AppendFormat(" {0}", string.Join(",", parameters.Select(o => o.ParameterName).ToArray()));
  296. foreach (var item in parameters)
  297. {
  298. cmd.Parameters.Add(item);
  299. }
  300. }
  301. cmd.Connection = conn;
  302. cmd.CommandText = sb.ToString();
  303. SqlDataAdapter adapter = new SqlDataAdapter(cmd);
  304. DataTable table = new DataTable();
  305. adapter.Fill(table);
  306.  
  307. conn.Close();//连接需要关闭
  308. return table;
  309. }
  310. catch (Exception ex)
  311. {
  312. throw ex;
  313. }
  314. finally
  315. {
  316. if (conn.State == ConnectionState.Open)
  317. conn.Close();
  318. }
  319. }
  320.  
  321. /// <summary>
  322. /// 返回Datatable数据集
  323. /// </summary>
  324. /// <param name="proName">存储过程名</param>
  325. /// <param name="parameters">参数列表</param>
  326. /// <returns></returns>
  327. [Obsolete("此方法已过时,请改用SqlQueryForDataTable")]
  328. public System.Data.DataTable ExecuteForDataTable(string proName, IDataParameter[] parameters)
  329. {
  330. try
  331. {
  332. SqlConnection conn = new System.Data.SqlClient.SqlConnection();
  333. conn.ConnectionString = Context.Database.Connection.ConnectionString;
  334. if (conn.State != ConnectionState.Open)
  335. {
  336. conn.Open();
  337. }
  338. SqlCommand cmd = new SqlCommand(proName, conn);
  339. cmd.CommandType = CommandType.StoredProcedure;
  340.  
  341. if (parameters != null && parameters.Length > )
  342. {
  343. foreach (var item in parameters)
  344. {
  345. cmd.Parameters.Add(item);
  346. }
  347. }
  348. SqlDataAdapter adapter = new SqlDataAdapter(cmd);
  349. DataTable table = new DataTable();
  350. adapter.Fill(table);
  351. return table;
  352. }
  353. catch (Exception ex)
  354. {
  355. throw ex;
  356. }
  357. }
  358. }

注意,我们在这个实现类中定义了一个私有方法,指明了数据库访问的上下文DbContext

DbContext类如下:

  1. public class DbContext : System.Data.Entity.DbContext
  2. {
  3. static DbContext()
  4. {
  5. //Database.SetInitializer(new CreateDatabaseIfNotExists<PersonalDbContext>());
  6. }
  7. public DbContext()
  8. : base("Name=DbContext")
  9. {
  10. }
  11.  
  12. protected override void OnModelCreating(DbModelBuilder modelBuilder)
  13. {
  14. var typesToRegister = Assembly.GetExecutingAssembly().GetTypes()
  15. .Where(type => !String.IsNullOrEmpty(type.Namespace))
  16. .Where(type => type.BaseType != null && type.BaseType.IsGenericType &&
  17. type.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>));
  18. foreach (var type in typesToRegister)
  19. {
  20. dynamic configurationInstance = Activator.CreateInstance(type);
  21. modelBuilder.Configurations.Add(configurationInstance);
  22. }
  23. }
  24. }

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

再configuration节点下面新建

  1. <connectionStrings>
  2. <add name="DbContext" providerName="System.Data.SqlClient" connectionString="Server=.;Database=Test;Uid=sa;Pwd=sa;"/>
  3. </connectionStrings>

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

  1. public static class DynamicQueryable
  2. {
  3. public static IQueryable<T> Where<T>(this IQueryable<T> source, string predicate, params object[] values)
  4. {
  5. return (IQueryable<T>)Where((IQueryable)source, predicate, values);
  6. }
  7.  
  8. public static IQueryable Where(this IQueryable source, string predicate, params object[] values)
  9. {
  10. if (source == null) throw new ArgumentNullException("source");
  11. if (predicate == null) throw new ArgumentNullException("predicate");
  12. LambdaExpression lambda = DynamicExpression.ParseLambda(source.ElementType, typeof(bool), predicate, values);
  13. return source.Provider.CreateQuery(
  14. Expression.Call(
  15. typeof(Queryable), "Where",
  16. new Type[] { source.ElementType },
  17. source.Expression, Expression.Quote(lambda)));
  18. }
  19.  
  20. public static IQueryable Select(this IQueryable source, string selector, params object[] values)
  21. {
  22. if (source == null) throw new ArgumentNullException("source");
  23. if (selector == null) throw new ArgumentNullException("selector");
  24. LambdaExpression lambda = DynamicExpression.ParseLambda(source.ElementType, null, selector, values);
  25. return source.Provider.CreateQuery(
  26. Expression.Call(
  27. typeof(Queryable), "Select",
  28. new Type[] { source.ElementType, lambda.Body.Type },
  29. source.Expression, Expression.Quote(lambda)));
  30. }
  31. public static IQueryable<dynamic> Select<T>(this IQueryable<T> source, string selector, params object[] values)
  32. {
  33. return (IQueryable<dynamic>)Select((IQueryable)source, selector, values);
  34. }
  35. public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string ordering, params object[] values)
  36. {
  37. return (IQueryable<T>)OrderBy((IQueryable)source, ordering, values);
  38. }
  39.  
  40. public static IQueryable<T> ThenBy<T>(this IQueryable<T> source, string ordering, params object[] values)
  41. {
  42. return (IQueryable<T>)ThenBy((IQueryable)source, ordering, values);
  43. }
  44.  
  45. public static IQueryable ThenBy(this IQueryable source, string ordering, params object[] values)
  46. {
  47. if (source == null) throw new ArgumentNullException("source");
  48. if (ordering == null) throw new ArgumentNullException("ordering");
  49. ParameterExpression[] parameters = new ParameterExpression[] {
  50. Expression.Parameter(source.ElementType, "") };
  51. ExpressionParser parser = new ExpressionParser(parameters, ordering, values);
  52. IEnumerable<DynamicOrdering> orderings = parser.ParseOrdering();
  53. Expression queryExpr = source.Expression;
  54. string methodAsc = "ThenBy";
  55. string methodDesc = "ThenByDescending";
  56. foreach (DynamicOrdering o in orderings)
  57. {
  58. queryExpr = Expression.Call(
  59. typeof(Queryable), o.Ascending ? methodAsc : methodDesc,
  60. new Type[] { source.ElementType, o.Selector.Type },
  61. queryExpr, Expression.Quote(Expression.Lambda(o.Selector, parameters)));
  62.  
  63. }
  64. return source.Provider.CreateQuery(queryExpr);
  65. }
  66.  
  67. public static IQueryable OrderBy(this IQueryable source, string ordering, params object[] values)
  68. {
  69. if (source == null) throw new ArgumentNullException("source");
  70. if (ordering == null) throw new ArgumentNullException("ordering");
  71. ParameterExpression[] parameters = new ParameterExpression[] {
  72. Expression.Parameter(source.ElementType, "") };
  73. ExpressionParser parser = new ExpressionParser(parameters, ordering, values);
  74. IEnumerable<DynamicOrdering> orderings = parser.ParseOrdering();
  75. Expression queryExpr = source.Expression;
  76. string methodAsc = "OrderBy";
  77. string methodDesc = "OrderByDescending";
  78. foreach (DynamicOrdering o in orderings)
  79. {
  80. queryExpr = Expression.Call(
  81. typeof(Queryable), o.Ascending ? methodAsc : methodDesc,
  82. new Type[] { source.ElementType, o.Selector.Type },
  83. queryExpr, Expression.Quote(Expression.Lambda(o.Selector, parameters)));
  84. methodAsc = "ThenBy";
  85. methodDesc = "ThenByDescending";
  86. }
  87. return source.Provider.CreateQuery(queryExpr);
  88. }
  89.  
  90. public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string propertyName, bool ascending)
  91. where T : class
  92. {
  93. Type type = typeof(T);
  94.  
  95. PropertyInfo property = type.GetProperty(propertyName);
  96. if (property == null)
  97. throw new ArgumentException("propertyName", "Not Exist");
  98.  
  99. ParameterExpression param = Expression.Parameter(type, "p");
  100. Expression propertyAccessExpression = Expression.MakeMemberAccess(param, property);
  101. LambdaExpression orderByExpression = Expression.Lambda(propertyAccessExpression, param);
  102.  
  103. string methodName = ascending ? "OrderBy" : "OrderByDescending";
  104.  
  105. MethodCallExpression resultExp = Expression.Call(typeof(Queryable), methodName,
  106. new Type[] { type, property.PropertyType }, source.Expression, Expression.Quote(orderByExpression));
  107.  
  108. return source.Provider.CreateQuery<T>(resultExp);
  109. }
  110.  
  111. public static IQueryable Take(this IQueryable source, int count)
  112. {
  113. if (source == null) throw new ArgumentNullException("source");
  114. return source.Provider.CreateQuery(
  115. Expression.Call(
  116. typeof(Queryable), "Take",
  117. new Type[] { source.ElementType },
  118. source.Expression, Expression.Constant(count)));
  119. }
  120.  
  121. public static IQueryable Skip(this IQueryable source, int count)
  122. {
  123. if (source == null) throw new ArgumentNullException("source");
  124. return source.Provider.CreateQuery(
  125. Expression.Call(
  126. typeof(Queryable), "Skip",
  127. new Type[] { source.ElementType },
  128. source.Expression, Expression.Constant(count)));
  129. }
  130.  
  131. public static IQueryable GroupBy(this IQueryable source, string keySelector, string elementSelector, params object[] values)
  132. {
  133. if (source == null) throw new ArgumentNullException("source");
  134. if (keySelector == null) throw new ArgumentNullException("keySelector");
  135. if (elementSelector == null) throw new ArgumentNullException("elementSelector");
  136. LambdaExpression keyLambda = DynamicExpression.ParseLambda(source.ElementType, null, keySelector, values);
  137. LambdaExpression elementLambda = DynamicExpression.ParseLambda(source.ElementType, null, elementSelector, values);
  138. return source.Provider.CreateQuery(
  139. Expression.Call(
  140. typeof(Queryable), "GroupBy",
  141. new Type[] { source.ElementType, keyLambda.Body.Type, elementLambda.Body.Type },
  142. source.Expression, Expression.Quote(keyLambda), Expression.Quote(elementLambda)));
  143. }
  144.  
  145. public static bool Any(this IQueryable source)
  146. {
  147. if (source == null) throw new ArgumentNullException("source");
  148. return (bool)source.Provider.Execute(
  149. Expression.Call(
  150. typeof(Queryable), "Any",
  151. new Type[] { source.ElementType }, source.Expression));
  152. }
  153.  
  154. public static int Count(this IQueryable source)
  155. {
  156. if (source == null) throw new ArgumentNullException("source");
  157. return (int)source.Provider.Execute(
  158. Expression.Call(
  159. typeof(Queryable), "Count",
  160. new Type[] { source.ElementType }, source.Expression));
  161. }
  162. }
  163.  
  164. public abstract class DynamicClass
  165. {
  166. public override string ToString()
  167. {
  168. PropertyInfo[] props = this.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
  169. StringBuilder sb = new StringBuilder();
  170. sb.Append("{");
  171. for (int i = ; i < props.Length; i++)
  172. {
  173. if (i > ) sb.Append(", ");
  174. sb.Append(props[i].Name);
  175. sb.Append("=");
  176. sb.Append(props[i].GetValue(this, null));
  177. }
  178. sb.Append("}");
  179. return sb.ToString();
  180. }
  181. }
  182.  
  183. public class DynamicProperty
  184. {
  185. string name;
  186. Type type;
  187.  
  188. public DynamicProperty(string name, Type type)
  189. {
  190. if (name == null) throw new ArgumentNullException("name");
  191. if (type == null) throw new ArgumentNullException("type");
  192. this.name = name;
  193. this.type = type;
  194. }
  195.  
  196. public string Name
  197. {
  198. get { return name; }
  199. }
  200.  
  201. public Type Type
  202. {
  203. get { return type; }
  204. }
  205. }
  206.  
  207. public static class DynamicExpression
  208. {
  209. public static Expression Parse(Type resultType, string expression, params object[] values)
  210. {
  211. ExpressionParser parser = new ExpressionParser(null, expression, values);
  212. return parser.Parse(resultType);
  213. }
  214.  
  215. public static LambdaExpression ParseLambda(Type itType, Type resultType, string expression, params object[] values)
  216. {
  217. return ParseLambda(new ParameterExpression[] { Expression.Parameter(itType, "") }, resultType, expression, values);
  218. }
  219.  
  220. public static LambdaExpression ParseLambda(ParameterExpression[] parameters, Type resultType, string expression, params object[] values)
  221. {
  222. ExpressionParser parser = new ExpressionParser(parameters, expression, values);
  223. return Expression.Lambda(parser.Parse(resultType), parameters);
  224. }
  225.  
  226. public static Expression<Func<T, S>> ParseLambda<T, S>(string expression, params object[] values)
  227. {
  228. return (Expression<Func<T, S>>)ParseLambda(typeof(T), typeof(S), expression, values);
  229. }
  230.  
  231. public static Type CreateClass(params DynamicProperty[] properties)
  232. {
  233. return ClassFactory.Instance.GetDynamicClass(properties);
  234. }
  235.  
  236. public static Type CreateClass(IEnumerable<DynamicProperty> properties)
  237. {
  238. return ClassFactory.Instance.GetDynamicClass(properties);
  239. }
  240. }
  241.  
  242. internal class DynamicOrdering
  243. {
  244. public Expression Selector;
  245. public bool Ascending;
  246. }
  247.  
  248. internal class Signature : IEquatable<Signature>
  249. {
  250. public DynamicProperty[] properties;
  251. public int hashCode;
  252.  
  253. public Signature(IEnumerable<DynamicProperty> properties)
  254. {
  255. this.properties = properties.ToArray();
  256. hashCode = ;
  257. foreach (DynamicProperty p in properties)
  258. {
  259. hashCode ^= p.Name.GetHashCode() ^ p.Type.GetHashCode();
  260. }
  261. }
  262.  
  263. public override int GetHashCode()
  264. {
  265. return hashCode;
  266. }
  267.  
  268. public override bool Equals(object obj)
  269. {
  270. return obj is Signature ? Equals((Signature)obj) : false;
  271. }
  272.  
  273. public bool Equals(Signature other)
  274. {
  275. if (properties.Length != other.properties.Length) return false;
  276. for (int i = ; i < properties.Length; i++)
  277. {
  278. if (properties[i].Name != other.properties[i].Name ||
  279. properties[i].Type != other.properties[i].Type) return false;
  280. }
  281. return true;
  282. }
  283. }
  284.  
  285. internal class ClassFactory
  286. {
  287. public static readonly ClassFactory Instance = new ClassFactory();
  288.  
  289. static ClassFactory() { } // Trigger lazy initialization of static fields
  290.  
  291. ModuleBuilder module;
  292. Dictionary<Signature, Type> classes;
  293. int classCount;
  294. ReaderWriterLock rwLock;
  295.  
  296. private ClassFactory()
  297. {
  298. AssemblyName name = new AssemblyName("DynamicClasses");
  299. AssemblyBuilder assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run);
  300. #if ENABLE_LINQ_PARTIAL_TRUST
  301. new ReflectionPermission(PermissionState.Unrestricted).Assert();
  302. #endif
  303. try
  304. {
  305. module = assembly.DefineDynamicModule("Module");
  306. }
  307. finally
  308. {
  309. #if ENABLE_LINQ_PARTIAL_TRUST
  310. PermissionSet.RevertAssert();
  311. #endif
  312. }
  313. classes = new Dictionary<Signature, Type>();
  314. rwLock = new ReaderWriterLock();
  315. }
  316.  
  317. public Type GetDynamicClass(IEnumerable<DynamicProperty> properties)
  318. {
  319. rwLock.AcquireReaderLock(Timeout.Infinite);
  320. try
  321. {
  322. Signature signature = new Signature(properties);
  323. Type type;
  324. if (!classes.TryGetValue(signature, out type))
  325. {
  326. type = CreateDynamicClass(signature.properties);
  327. classes.Add(signature, type);
  328. }
  329. return type;
  330. }
  331. finally
  332. {
  333. rwLock.ReleaseReaderLock();
  334. }
  335. }
  336.  
  337. Type CreateDynamicClass(DynamicProperty[] properties)
  338. {
  339. LockCookie cookie = rwLock.UpgradeToWriterLock(Timeout.Infinite);
  340. try
  341. {
  342. string typeName = "DynamicClass" + (classCount + );
  343. #if ENABLE_LINQ_PARTIAL_TRUST
  344. new ReflectionPermission(PermissionState.Unrestricted).Assert();
  345. #endif
  346. try
  347. {
  348. TypeBuilder tb = this.module.DefineType(typeName, TypeAttributes.Class |
  349. TypeAttributes.Public, typeof(DynamicClass));
  350. FieldInfo[] fields = GenerateProperties(tb, properties);
  351. GenerateEquals(tb, fields);
  352. GenerateGetHashCode(tb, fields);
  353. Type result = tb.CreateType();
  354. classCount++;
  355. return result;
  356. }
  357. finally
  358. {
  359. #if ENABLE_LINQ_PARTIAL_TRUST
  360. PermissionSet.RevertAssert();
  361. #endif
  362. }
  363. }
  364. finally
  365. {
  366. rwLock.DowngradeFromWriterLock(ref cookie);
  367. }
  368. }
  369.  
  370. FieldInfo[] GenerateProperties(TypeBuilder tb, DynamicProperty[] properties)
  371. {
  372. FieldInfo[] fields = new FieldBuilder[properties.Length];
  373. for (int i = ; i < properties.Length; i++)
  374. {
  375. DynamicProperty dp = properties[i];
  376. FieldBuilder fb = tb.DefineField("_" + dp.Name, dp.Type, FieldAttributes.Private);
  377. PropertyBuilder pb = tb.DefineProperty(dp.Name, PropertyAttributes.HasDefault, dp.Type, null);
  378. MethodBuilder mbGet = tb.DefineMethod("get_" + dp.Name,
  379. MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
  380. dp.Type, Type.EmptyTypes);
  381. ILGenerator genGet = mbGet.GetILGenerator();
  382. genGet.Emit(OpCodes.Ldarg_0);
  383. genGet.Emit(OpCodes.Ldfld, fb);
  384. genGet.Emit(OpCodes.Ret);
  385. MethodBuilder mbSet = tb.DefineMethod("set_" + dp.Name,
  386. MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
  387. null, new Type[] { dp.Type });
  388. ILGenerator genSet = mbSet.GetILGenerator();
  389. genSet.Emit(OpCodes.Ldarg_0);
  390. genSet.Emit(OpCodes.Ldarg_1);
  391. genSet.Emit(OpCodes.Stfld, fb);
  392. genSet.Emit(OpCodes.Ret);
  393. pb.SetGetMethod(mbGet);
  394. pb.SetSetMethod(mbSet);
  395. fields[i] = fb;
  396. }
  397. return fields;
  398. }
  399.  
  400. void GenerateEquals(TypeBuilder tb, FieldInfo[] fields)
  401. {
  402. MethodBuilder mb = tb.DefineMethod("Equals",
  403. MethodAttributes.Public | MethodAttributes.ReuseSlot |
  404. MethodAttributes.Virtual | MethodAttributes.HideBySig,
  405. typeof(bool), new Type[] { typeof(object) });
  406. ILGenerator gen = mb.GetILGenerator();
  407. LocalBuilder other = gen.DeclareLocal(tb);
  408. Label next = gen.DefineLabel();
  409. gen.Emit(OpCodes.Ldarg_1);
  410. gen.Emit(OpCodes.Isinst, tb);
  411. gen.Emit(OpCodes.Stloc, other);
  412. gen.Emit(OpCodes.Ldloc, other);
  413. gen.Emit(OpCodes.Brtrue_S, next);
  414. gen.Emit(OpCodes.Ldc_I4_0);
  415. gen.Emit(OpCodes.Ret);
  416. gen.MarkLabel(next);
  417. foreach (FieldInfo field in fields)
  418. {
  419. Type ft = field.FieldType;
  420. Type ct = typeof(EqualityComparer<>).MakeGenericType(ft);
  421. next = gen.DefineLabel();
  422. gen.EmitCall(OpCodes.Call, ct.GetMethod("get_Default"), null);
  423. gen.Emit(OpCodes.Ldarg_0);
  424. gen.Emit(OpCodes.Ldfld, field);
  425. gen.Emit(OpCodes.Ldloc, other);
  426. gen.Emit(OpCodes.Ldfld, field);
  427. gen.EmitCall(OpCodes.Callvirt, ct.GetMethod("Equals", new Type[] { ft, ft }), null);
  428. gen.Emit(OpCodes.Brtrue_S, next);
  429. gen.Emit(OpCodes.Ldc_I4_0);
  430. gen.Emit(OpCodes.Ret);
  431. gen.MarkLabel(next);
  432. }
  433. gen.Emit(OpCodes.Ldc_I4_1);
  434. gen.Emit(OpCodes.Ret);
  435. }
  436.  
  437. void GenerateGetHashCode(TypeBuilder tb, FieldInfo[] fields)
  438. {
  439. MethodBuilder mb = tb.DefineMethod("GetHashCode",
  440. MethodAttributes.Public | MethodAttributes.ReuseSlot |
  441. MethodAttributes.Virtual | MethodAttributes.HideBySig,
  442. typeof(int), Type.EmptyTypes);
  443. ILGenerator gen = mb.GetILGenerator();
  444. gen.Emit(OpCodes.Ldc_I4_0);
  445. foreach (FieldInfo field in fields)
  446. {
  447. Type ft = field.FieldType;
  448. Type ct = typeof(EqualityComparer<>).MakeGenericType(ft);
  449. gen.EmitCall(OpCodes.Call, ct.GetMethod("get_Default"), null);
  450. gen.Emit(OpCodes.Ldarg_0);
  451. gen.Emit(OpCodes.Ldfld, field);
  452. gen.EmitCall(OpCodes.Callvirt, ct.GetMethod("GetHashCode", new Type[] { ft }), null);
  453. gen.Emit(OpCodes.Xor);
  454. }
  455. gen.Emit(OpCodes.Ret);
  456. }
  457. }
  458.  
  459. public sealed class ParseException : Exception
  460. {
  461. int position;
  462.  
  463. public ParseException(string message, int position)
  464. : base(message)
  465. {
  466. this.position = position;
  467. }
  468.  
  469. public int Position
  470. {
  471. get { return position; }
  472. }
  473.  
  474. public override string ToString()
  475. {
  476. return string.Format(Res.ParseExceptionFormat, Message, position);
  477. }
  478. }
  479.  
  480. internal class ExpressionParser
  481. {
  482. struct Token
  483. {
  484. public TokenId id;
  485. public string text;
  486. public int pos;
  487. }
  488.  
  489. enum TokenId
  490. {
  491. Unknown,
  492. End,
  493. Identifier,
  494. StringLiteral,
  495. IntegerLiteral,
  496. RealLiteral,
  497. Exclamation,
  498. Percent,
  499. Amphersand,
  500. OpenParen,
  501. CloseParen,
  502. Asterisk,
  503. Plus,
  504. Comma,
  505. Minus,
  506. Dot,
  507. Slash,
  508. Colon,
  509. LessThan,
  510. Equal,
  511. GreaterThan,
  512. Question,
  513. OpenBracket,
  514. CloseBracket,
  515. Bar,
  516. ExclamationEqual,
  517. DoubleAmphersand,
  518. LessThanEqual,
  519. LessGreater,
  520. DoubleEqual,
  521. GreaterThanEqual,
  522. DoubleBar
  523. }
  524.  
  525. interface ILogicalSignatures
  526. {
  527. void F(bool x, bool y);
  528. void F(bool? x, bool? y);
  529. }
  530.  
  531. interface IArithmeticSignatures
  532. {
  533. void F(int x, int y);
  534. void F(uint x, uint y);
  535. void F(long x, long y);
  536. void F(ulong x, ulong y);
  537. void F(float x, float y);
  538. void F(double x, double y);
  539. void F(decimal x, decimal y);
  540. void F(int? x, int? y);
  541. void F(uint? x, uint? y);
  542. void F(long? x, long? y);
  543. void F(ulong? x, ulong? y);
  544. void F(float? x, float? y);
  545. void F(double? x, double? y);
  546. void F(decimal? x, decimal? y);
  547. }
  548.  
  549. interface IRelationalSignatures : IArithmeticSignatures
  550. {
  551. void F(string x, string y);
  552. void F(char x, char y);
  553. void F(DateTime x, DateTime y);
  554. void F(TimeSpan x, TimeSpan y);
  555. void F(char? x, char? y);
  556. void F(DateTime? x, DateTime? y);
  557. void F(TimeSpan? x, TimeSpan? y);
  558. }
  559.  
  560. interface IEqualitySignatures : IRelationalSignatures
  561. {
  562. void F(bool x, bool y);
  563. void F(bool? x, bool? y);
  564. }
  565.  
  566. interface IAddSignatures : IArithmeticSignatures
  567. {
  568. void F(DateTime x, TimeSpan y);
  569. void F(TimeSpan x, TimeSpan y);
  570. void F(DateTime? x, TimeSpan? y);
  571. void F(TimeSpan? x, TimeSpan? y);
  572. }
  573.  
  574. interface ISubtractSignatures : IAddSignatures
  575. {
  576. void F(DateTime x, DateTime y);
  577. void F(DateTime? x, DateTime? y);
  578. }
  579.  
  580. interface INegationSignatures
  581. {
  582. void F(int x);
  583. void F(long x);
  584. void F(float x);
  585. void F(double x);
  586. void F(decimal x);
  587. void F(int? x);
  588. void F(long? x);
  589. void F(float? x);
  590. void F(double? x);
  591. void F(decimal? x);
  592. }
  593.  
  594. interface INotSignatures
  595. {
  596. void F(bool x);
  597. void F(bool? x);
  598. }
  599.  
  600. interface IEnumerableSignatures
  601. {
  602. void Where(bool predicate);
  603. void Any();
  604. void Any(bool predicate);
  605. void All(bool predicate);
  606. void Count();
  607. void Count(bool predicate);
  608. void Min(object selector);
  609. void Max(object selector);
  610. void Sum(int selector);
  611. void Sum(int? selector);
  612. void Sum(long selector);
  613. void Sum(long? selector);
  614. void Sum(float selector);
  615. void Sum(float? selector);
  616. void Sum(double selector);
  617. void Sum(double? selector);
  618. void Sum(decimal selector);
  619. void Sum(decimal? selector);
  620. void Average(int selector);
  621. void Average(int? selector);
  622. void Average(long selector);
  623. void Average(long? selector);
  624. void Average(float selector);
  625. void Average(float? selector);
  626. void Average(double selector);
  627. void Average(double? selector);
  628. void Average(decimal selector);
  629. void Average(decimal? selector);
  630. }
  631.  
  632. static readonly Type[] predefinedTypes = {
  633. typeof(Object),
  634. typeof(Boolean),
  635. typeof(Char),
  636. typeof(String),
  637. typeof(SByte),
  638. typeof(Byte),
  639. typeof(Int16),
  640. typeof(UInt16),
  641. typeof(Int32),
  642. typeof(UInt32),
  643. typeof(Int64),
  644. typeof(UInt64),
  645. typeof(Single),
  646. typeof(Double),
  647. typeof(Decimal),
  648. typeof(DateTime),
  649. typeof(TimeSpan),
  650. typeof(Guid),
  651. typeof(Math),
  652. typeof(Convert)
  653. };
  654.  
  655. static readonly Expression trueLiteral = Expression.Constant(true);
  656. static readonly Expression falseLiteral = Expression.Constant(false);
  657. static readonly Expression nullLiteral = Expression.Constant(null);
  658.  
  659. static readonly string keywordIt = "it";
  660. static readonly string keywordIif = "iif";
  661. static readonly string keywordNew = "new";
  662.  
  663. static Dictionary<string, object> keywords;
  664.  
  665. Dictionary<string, object> symbols;
  666. IDictionary<string, object> externals;
  667. Dictionary<Expression, string> literals;
  668. ParameterExpression it;
  669. string text;
  670. int textPos;
  671. int textLen;
  672. char ch;
  673. Token token;
  674.  
  675. public ExpressionParser(ParameterExpression[] parameters, string expression, object[] values)
  676. {
  677. if (expression == null) throw new ArgumentNullException("expression");
  678. if (keywords == null) keywords = CreateKeywords();
  679. symbols = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
  680. literals = new Dictionary<Expression, string>();
  681. if (parameters != null) ProcessParameters(parameters);
  682. if (values != null) ProcessValues(values);
  683. text = expression;
  684. textLen = text.Length;
  685. SetTextPos();
  686. NextToken();
  687. }
  688.  
  689. void ProcessParameters(ParameterExpression[] parameters)
  690. {
  691. foreach (ParameterExpression pe in parameters)
  692. if (!String.IsNullOrEmpty(pe.Name))
  693. AddSymbol(pe.Name, pe);
  694. if (parameters.Length == && String.IsNullOrEmpty(parameters[].Name))
  695. it = parameters[];
  696. }
  697.  
  698. void ProcessValues(object[] values)
  699. {
  700. for (int i = ; i < values.Length; i++)
  701. {
  702. object value = values[i];
  703. if (i == values.Length - && value is IDictionary<string, object>)
  704. {
  705. externals = (IDictionary<string, object>)value;
  706. }
  707. else
  708. {
  709. AddSymbol("@" + i.ToString(System.Globalization.CultureInfo.InvariantCulture), value);
  710. }
  711. }
  712. }
  713.  
  714. void AddSymbol(string name, object value)
  715. {
  716. if (symbols.ContainsKey(name))
  717. throw ParseError(Res.DuplicateIdentifier, name);
  718. symbols.Add(name, value);
  719. }
  720.  
  721. public Expression Parse(Type resultType)
  722. {
  723. int exprPos = token.pos;
  724. Expression expr = ParseExpression();
  725. if (resultType != null)
  726. if ((expr = PromoteExpression(expr, resultType, true)) == null)
  727. throw ParseError(exprPos, Res.ExpressionTypeMismatch, GetTypeName(resultType));
  728. ValidateToken(TokenId.End, Res.SyntaxError);
  729. return expr;
  730. }
  731.  
  732. #pragma warning disable 0219
  733. public IEnumerable<DynamicOrdering> ParseOrdering()
  734. {
  735. List<DynamicOrdering> orderings = new List<DynamicOrdering>();
  736. while (true)
  737. {
  738. Expression expr = ParseExpression();
  739. bool ascending = true;
  740. if (TokenIdentifierIs("asc") || TokenIdentifierIs("ascending"))
  741. {
  742. NextToken();
  743. }
  744. else if (TokenIdentifierIs("desc") || TokenIdentifierIs("descending"))
  745. {
  746. NextToken();
  747. ascending = false;
  748. }
  749. orderings.Add(new DynamicOrdering { Selector = expr, Ascending = ascending });
  750. if (token.id != TokenId.Comma) break;
  751. NextToken();
  752. }
  753. ValidateToken(TokenId.End, Res.SyntaxError);
  754. return orderings;
  755. }
  756. #pragma warning restore 0219
  757.  
  758. // ?: operator
  759. Expression ParseExpression()
  760. {
  761. int errorPos = token.pos;
  762. Expression expr = ParseLogicalOr();
  763. if (token.id == TokenId.Question)
  764. {
  765. NextToken();
  766. Expression expr1 = ParseExpression();
  767. ValidateToken(TokenId.Colon, Res.ColonExpected);
  768. NextToken();
  769. Expression expr2 = ParseExpression();
  770. expr = GenerateConditional(expr, expr1, expr2, errorPos);
  771. }
  772. return expr;
  773. }
  774.  
  775. // ||, or operator
  776. Expression ParseLogicalOr()
  777. {
  778. Expression left = ParseLogicalAnd();
  779. while (token.id == TokenId.DoubleBar || TokenIdentifierIs("or"))
  780. {
  781. Token op = token;
  782. NextToken();
  783. Expression right = ParseLogicalAnd();
  784. CheckAndPromoteOperands(typeof(ILogicalSignatures), op.text, ref left, ref right, op.pos);
  785. left = Expression.OrElse(left, right);
  786. }
  787. return left;
  788. }
  789.  
  790. // &&, and operator
  791. Expression ParseLogicalAnd()
  792. {
  793. Expression left = ParseComparison();
  794. while (token.id == TokenId.DoubleAmphersand || TokenIdentifierIs("and"))
  795. {
  796. Token op = token;
  797. NextToken();
  798. Expression right = ParseComparison();
  799. CheckAndPromoteOperands(typeof(ILogicalSignatures), op.text, ref left, ref right, op.pos);
  800. left = Expression.AndAlso(left, right);
  801. }
  802. return left;
  803. }
  804.  
  805. // =, ==, !=, <>, >, >=, <, <= operators
  806. Expression ParseComparison()
  807. {
  808. Expression left = ParseAdditive();
  809. while (token.id == TokenId.Equal || token.id == TokenId.DoubleEqual ||
  810. token.id == TokenId.ExclamationEqual || token.id == TokenId.LessGreater ||
  811. token.id == TokenId.GreaterThan || token.id == TokenId.GreaterThanEqual ||
  812. token.id == TokenId.LessThan || token.id == TokenId.LessThanEqual)
  813. {
  814. Token op = token;
  815. NextToken();
  816. Expression right = ParseAdditive();
  817. bool isEquality = op.id == TokenId.Equal || op.id == TokenId.DoubleEqual ||
  818. op.id == TokenId.ExclamationEqual || op.id == TokenId.LessGreater;
  819. if (isEquality && !left.Type.IsValueType && !right.Type.IsValueType)
  820. {
  821. if (left.Type != right.Type)
  822. {
  823. if (left.Type.IsAssignableFrom(right.Type))
  824. {
  825. right = Expression.Convert(right, left.Type);
  826. }
  827. else if (right.Type.IsAssignableFrom(left.Type))
  828. {
  829. left = Expression.Convert(left, right.Type);
  830. }
  831. else
  832. {
  833. throw IncompatibleOperandsError(op.text, left, right, op.pos);
  834. }
  835. }
  836. }
  837. else if (IsEnumType(left.Type) || IsEnumType(right.Type))
  838. {
  839. if (left.Type != right.Type)
  840. {
  841. Expression e;
  842. if ((e = PromoteExpression(right, left.Type, true)) != null)
  843. {
  844. right = e;
  845. }
  846. else if ((e = PromoteExpression(left, right.Type, true)) != null)
  847. {
  848. left = e;
  849. }
  850. else
  851. {
  852. throw IncompatibleOperandsError(op.text, left, right, op.pos);
  853. }
  854. }
  855. }
  856. else
  857. {
  858. CheckAndPromoteOperands(isEquality ? typeof(IEqualitySignatures) : typeof(IRelationalSignatures),
  859. op.text, ref left, ref right, op.pos);
  860. }
  861. switch (op.id)
  862. {
  863. case TokenId.Equal:
  864. case TokenId.DoubleEqual:
  865. left = GenerateEqual(left, right);
  866. break;
  867. case TokenId.ExclamationEqual:
  868. case TokenId.LessGreater:
  869. left = GenerateNotEqual(left, right);
  870. break;
  871. case TokenId.GreaterThan:
  872. left = GenerateGreaterThan(left, right);
  873. break;
  874. case TokenId.GreaterThanEqual:
  875. left = GenerateGreaterThanEqual(left, right);
  876. break;
  877. case TokenId.LessThan:
  878. left = GenerateLessThan(left, right);
  879. break;
  880. case TokenId.LessThanEqual:
  881. left = GenerateLessThanEqual(left, right);
  882. break;
  883. }
  884. }
  885. return left;
  886. }
  887.  
  888. // +, -, & operators
  889. Expression ParseAdditive()
  890. {
  891. Expression left = ParseMultiplicative();
  892. while (token.id == TokenId.Plus || token.id == TokenId.Minus ||
  893. token.id == TokenId.Amphersand)
  894. {
  895. Token op = token;
  896. NextToken();
  897. Expression right = ParseMultiplicative();
  898. switch (op.id)
  899. {
  900. case TokenId.Plus:
  901. if (left.Type == typeof(string) || right.Type == typeof(string))
  902. goto case TokenId.Amphersand;
  903. CheckAndPromoteOperands(typeof(IAddSignatures), op.text, ref left, ref right, op.pos);
  904. left = GenerateAdd(left, right);
  905. break;
  906. case TokenId.Minus:
  907. CheckAndPromoteOperands(typeof(ISubtractSignatures), op.text, ref left, ref right, op.pos);
  908. left = GenerateSubtract(left, right);
  909. break;
  910. case TokenId.Amphersand:
  911. left = GenerateStringConcat(left, right);
  912. break;
  913. }
  914. }
  915. return left;
  916. }
  917.  
  918. // *, /, %, mod operators
  919. Expression ParseMultiplicative()
  920. {
  921. Expression left = ParseUnary();
  922. while (token.id == TokenId.Asterisk || token.id == TokenId.Slash ||
  923. token.id == TokenId.Percent || TokenIdentifierIs("mod"))
  924. {
  925. Token op = token;
  926. NextToken();
  927. Expression right = ParseUnary();
  928. CheckAndPromoteOperands(typeof(IArithmeticSignatures), op.text, ref left, ref right, op.pos);
  929. switch (op.id)
  930. {
  931. case TokenId.Asterisk:
  932. left = Expression.Multiply(left, right);
  933. break;
  934. case TokenId.Slash:
  935. left = Expression.Divide(left, right);
  936. break;
  937. case TokenId.Percent:
  938. case TokenId.Identifier:
  939. left = Expression.Modulo(left, right);
  940. break;
  941. }
  942. }
  943. return left;
  944. }
  945.  
  946. // -, !, not unary operators
  947. Expression ParseUnary()
  948. {
  949. if (token.id == TokenId.Minus || token.id == TokenId.Exclamation ||
  950. TokenIdentifierIs("not"))
  951. {
  952. Token op = token;
  953. NextToken();
  954. if (op.id == TokenId.Minus && (token.id == TokenId.IntegerLiteral ||
  955. token.id == TokenId.RealLiteral))
  956. {
  957. token.text = "-" + token.text;
  958. token.pos = op.pos;
  959. return ParsePrimary();
  960. }
  961. Expression expr = ParseUnary();
  962. if (op.id == TokenId.Minus)
  963. {
  964. CheckAndPromoteOperand(typeof(INegationSignatures), op.text, ref expr, op.pos);
  965. expr = Expression.Negate(expr);
  966. }
  967. else
  968. {
  969. CheckAndPromoteOperand(typeof(INotSignatures), op.text, ref expr, op.pos);
  970. expr = Expression.Not(expr);
  971. }
  972. return expr;
  973. }
  974. return ParsePrimary();
  975. }
  976.  
  977. Expression ParsePrimary()
  978. {
  979. Expression expr = ParsePrimaryStart();
  980. while (true)
  981. {
  982. if (token.id == TokenId.Dot)
  983. {
  984. NextToken();
  985. expr = ParseMemberAccess(null, expr);
  986. }
  987. else if (token.id == TokenId.OpenBracket)
  988. {
  989. expr = ParseElementAccess(expr);
  990. }
  991. else
  992. {
  993. break;
  994. }
  995. }
  996. return expr;
  997. }
  998.  
  999. Expression ParsePrimaryStart()
  1000. {
  1001. switch (token.id)
  1002. {
  1003. case TokenId.Identifier:
  1004. return ParseIdentifier();
  1005. case TokenId.StringLiteral:
  1006. return ParseStringLiteral();
  1007. case TokenId.IntegerLiteral:
  1008. return ParseIntegerLiteral();
  1009. case TokenId.RealLiteral:
  1010. return ParseRealLiteral();
  1011. case TokenId.OpenParen:
  1012. return ParseParenExpression();
  1013. default:
  1014. throw ParseError(Res.ExpressionExpected);
  1015. }
  1016. }
  1017.  
  1018. Expression ParseStringLiteral()
  1019. {
  1020. ValidateToken(TokenId.StringLiteral);
  1021. char quote = token.text[];
  1022. string s = token.text.Substring(, token.text.Length - );
  1023. int start = ;
  1024. while (true)
  1025. {
  1026. int i = s.IndexOf(quote, start);
  1027. if (i < ) break;
  1028. s = s.Remove(i, );
  1029. start = i + ;
  1030. }
  1031. //if (quote == '\'') {
  1032. // if (s.Length != 1)
  1033. // throw ParseError(Res.InvalidCharacterLiteral);
  1034. // NextToken();
  1035. // return CreateLiteral(s[0], s);
  1036. //}
  1037. NextToken();
  1038. return CreateLiteral(s, s);
  1039. }
  1040.  
  1041. Expression ParseIntegerLiteral()
  1042. {
  1043. ValidateToken(TokenId.IntegerLiteral);
  1044. string text = token.text;
  1045. if (text[] != '-')
  1046. {
  1047. ulong value;
  1048. if (!UInt64.TryParse(text, out value))
  1049. throw ParseError(Res.InvalidIntegerLiteral, text);
  1050. NextToken();
  1051. if (value <= (ulong)Int32.MaxValue) return CreateLiteral((int)value, text);
  1052. if (value <= (ulong)UInt32.MaxValue) return CreateLiteral((uint)value, text);
  1053. if (value <= (ulong)Int64.MaxValue) return CreateLiteral((long)value, text);
  1054. return CreateLiteral(value, text);
  1055. }
  1056. else
  1057. {
  1058. long value;
  1059. if (!Int64.TryParse(text, out value))
  1060. throw ParseError(Res.InvalidIntegerLiteral, text);
  1061. NextToken();
  1062. if (value >= Int32.MinValue && value <= Int32.MaxValue)
  1063. return CreateLiteral((int)value, text);
  1064. return CreateLiteral(value, text);
  1065. }
  1066. }
  1067.  
  1068. Expression ParseRealLiteral()
  1069. {
  1070. ValidateToken(TokenId.RealLiteral);
  1071. string text = token.text;
  1072. object value = null;
  1073. char last = text[text.Length - ];
  1074. if (last == 'F' || last == 'f')
  1075. {
  1076. float f;
  1077. if (Single.TryParse(text.Substring(, text.Length - ), out f)) value = f;
  1078. }
  1079. else
  1080. {
  1081. double d;
  1082. if (Double.TryParse(text, out d)) value = d;
  1083. }
  1084. if (value == null) throw ParseError(Res.InvalidRealLiteral, text);
  1085. NextToken();
  1086. return CreateLiteral(value, text);
  1087. }
  1088.  
  1089. Expression CreateLiteral(object value, string text)
  1090. {
  1091. ConstantExpression expr = Expression.Constant(value);
  1092. literals.Add(expr, text);
  1093. return expr;
  1094. }
  1095.  
  1096. Expression ParseParenExpression()
  1097. {
  1098. ValidateToken(TokenId.OpenParen, Res.OpenParenExpected);
  1099. NextToken();
  1100. Expression e = ParseExpression();
  1101. ValidateToken(TokenId.CloseParen, Res.CloseParenOrOperatorExpected);
  1102. NextToken();
  1103. return e;
  1104. }
  1105.  
  1106. Expression ParseIdentifier()
  1107. {
  1108. ValidateToken(TokenId.Identifier);
  1109. object value;
  1110. if (keywords.TryGetValue(token.text, out value))
  1111. {
  1112. if (value is Type) return ParseTypeAccess((Type)value);
  1113. if (value == (object)keywordIt) return ParseIt();
  1114. if (value == (object)keywordIif) return ParseIif();
  1115. if (value == (object)keywordNew) return ParseNew();
  1116. NextToken();
  1117. return (Expression)value;
  1118. }
  1119. if (symbols.TryGetValue(token.text, out value) ||
  1120. externals != null && externals.TryGetValue(token.text, out value))
  1121. {
  1122. Expression expr = value as Expression;
  1123. if (expr == null)
  1124. {
  1125. expr = Expression.Constant(value);
  1126. }
  1127. else
  1128. {
  1129. LambdaExpression lambda = expr as LambdaExpression;
  1130. if (lambda != null) return ParseLambdaInvocation(lambda);
  1131. }
  1132. NextToken();
  1133. return expr;
  1134. }
  1135. if (it != null) return ParseMemberAccess(null, it);
  1136. throw ParseError(Res.UnknownIdentifier, token.text);
  1137. }
  1138.  
  1139. Expression ParseIt()
  1140. {
  1141. if (it == null)
  1142. throw ParseError(Res.NoItInScope);
  1143. NextToken();
  1144. return it;
  1145. }
  1146.  
  1147. Expression ParseIif()
  1148. {
  1149. int errorPos = token.pos;
  1150. NextToken();
  1151. Expression[] args = ParseArgumentList();
  1152. if (args.Length != )
  1153. throw ParseError(errorPos, Res.IifRequiresThreeArgs);
  1154. return GenerateConditional(args[], args[], args[], errorPos);
  1155. }
  1156.  
  1157. Expression GenerateConditional(Expression test, Expression expr1, Expression expr2, int errorPos)
  1158. {
  1159. if (test.Type != typeof(bool))
  1160. throw ParseError(errorPos, Res.FirstExprMustBeBool);
  1161. if (expr1.Type != expr2.Type)
  1162. {
  1163. Expression expr1as2 = expr2 != nullLiteral ? PromoteExpression(expr1, expr2.Type, true) : null;
  1164. Expression expr2as1 = expr1 != nullLiteral ? PromoteExpression(expr2, expr1.Type, true) : null;
  1165. if (expr1as2 != null && expr2as1 == null)
  1166. {
  1167. expr1 = expr1as2;
  1168. }
  1169. else if (expr2as1 != null && expr1as2 == null)
  1170. {
  1171. expr2 = expr2as1;
  1172. }
  1173. else
  1174. {
  1175. string type1 = expr1 != nullLiteral ? expr1.Type.Name : "null";
  1176. string type2 = expr2 != nullLiteral ? expr2.Type.Name : "null";
  1177. if (expr1as2 != null && expr2as1 != null)
  1178. throw ParseError(errorPos, Res.BothTypesConvertToOther, type1, type2);
  1179. throw ParseError(errorPos, Res.NeitherTypeConvertsToOther, type1, type2);
  1180. }
  1181. }
  1182. return Expression.Condition(test, expr1, expr2);
  1183. }
  1184.  
  1185. Expression ParseNew()
  1186. {
  1187. NextToken();
  1188. ValidateToken(TokenId.OpenParen, Res.OpenParenExpected);
  1189. NextToken();
  1190. List<DynamicProperty> properties = new List<DynamicProperty>();
  1191. List<Expression> expressions = new List<Expression>();
  1192. while (true)
  1193. {
  1194. int exprPos = token.pos;
  1195. Expression expr = ParseExpression();
  1196. string propName;
  1197. if (TokenIdentifierIs("as"))
  1198. {
  1199. NextToken();
  1200. propName = GetIdentifier();
  1201. NextToken();
  1202. }
  1203. else
  1204. {
  1205. MemberExpression me = expr as MemberExpression;
  1206. if (me == null) throw ParseError(exprPos, Res.MissingAsClause);
  1207. propName = me.Member.Name;
  1208. }
  1209. expressions.Add(expr);
  1210. properties.Add(new DynamicProperty(propName, expr.Type));
  1211. if (token.id != TokenId.Comma) break;
  1212. NextToken();
  1213. }
  1214. ValidateToken(TokenId.CloseParen, Res.CloseParenOrCommaExpected);
  1215. NextToken();
  1216. Type type = DynamicExpression.CreateClass(properties);
  1217. MemberBinding[] bindings = new MemberBinding[properties.Count];
  1218. for (int i = ; i < bindings.Length; i++)
  1219. bindings[i] = Expression.Bind(type.GetProperty(properties[i].Name), expressions[i]);
  1220. return Expression.MemberInit(Expression.New(type), bindings);
  1221. }
  1222.  
  1223. Expression ParseLambdaInvocation(LambdaExpression lambda)
  1224. {
  1225. int errorPos = token.pos;
  1226. NextToken();
  1227. Expression[] args = ParseArgumentList();
  1228. MethodBase method;
  1229. if (FindMethod(lambda.Type, "Invoke", false, args, out method) != )
  1230. throw ParseError(errorPos, Res.ArgsIncompatibleWithLambda);
  1231. return Expression.Invoke(lambda, args);
  1232. }
  1233.  
  1234. Expression ParseTypeAccess(Type type)
  1235. {
  1236. int errorPos = token.pos;
  1237. NextToken();
  1238. if (token.id == TokenId.Question)
  1239. {
  1240. if (!type.IsValueType || IsNullableType(type))
  1241. throw ParseError(errorPos, Res.TypeHasNoNullableForm, GetTypeName(type));
  1242. type = typeof(Nullable<>).MakeGenericType(type);
  1243. NextToken();
  1244. }
  1245. if (token.id == TokenId.OpenParen)
  1246. {
  1247. Expression[] args = ParseArgumentList();
  1248. MethodBase method;
  1249. switch (FindBestMethod(type.GetConstructors(), args, out method))
  1250. {
  1251. case :
  1252. if (args.Length == )
  1253. return GenerateConversion(args[], type, errorPos);
  1254. throw ParseError(errorPos, Res.NoMatchingConstructor, GetTypeName(type));
  1255. case :
  1256. return Expression.New((ConstructorInfo)method, args);
  1257. default:
  1258. throw ParseError(errorPos, Res.AmbiguousConstructorInvocation, GetTypeName(type));
  1259. }
  1260. }
  1261. ValidateToken(TokenId.Dot, Res.DotOrOpenParenExpected);
  1262. NextToken();
  1263. return ParseMemberAccess(type, null);
  1264. }
  1265.  
  1266. Expression GenerateConversion(Expression expr, Type type, int errorPos)
  1267. {
  1268. Type exprType = expr.Type;
  1269. if (exprType == type) return expr;
  1270. if (exprType.IsValueType && type.IsValueType)
  1271. {
  1272. if ((IsNullableType(exprType) || IsNullableType(type)) &&
  1273. GetNonNullableType(exprType) == GetNonNullableType(type))
  1274. return Expression.Convert(expr, type);
  1275. if ((IsNumericType(exprType) || IsEnumType(exprType)) &&
  1276. (IsNumericType(type)) || IsEnumType(type))
  1277. return Expression.ConvertChecked(expr, type);
  1278. }
  1279. if (exprType.IsAssignableFrom(type) || type.IsAssignableFrom(exprType) ||
  1280. exprType.IsInterface || type.IsInterface)
  1281. return Expression.Convert(expr, type);
  1282. throw ParseError(errorPos, Res.CannotConvertValue,
  1283. GetTypeName(exprType), GetTypeName(type));
  1284. }
  1285.  
  1286. Expression ParseMemberAccess(Type type, Expression instance)
  1287. {
  1288. if (instance != null) type = instance.Type;
  1289. int errorPos = token.pos;
  1290. string id = GetIdentifier();
  1291. NextToken();
  1292. if (token.id == TokenId.OpenParen)
  1293. {
  1294. if (instance != null && type != typeof(string))
  1295. {
  1296. Type enumerableType = FindGenericType(typeof(IEnumerable<>), type);
  1297. if (enumerableType != null)
  1298. {
  1299. Type elementType = enumerableType.GetGenericArguments()[];
  1300. return ParseAggregate(instance, elementType, id, errorPos);
  1301. }
  1302. }
  1303. Expression[] args = ParseArgumentList();
  1304. MethodBase mb;
  1305. switch (FindMethod(type, id, instance == null, args, out mb))
  1306. {
  1307. case :
  1308. throw ParseError(errorPos, Res.NoApplicableMethod,
  1309. id, GetTypeName(type));
  1310. case :
  1311. MethodInfo method = (MethodInfo)mb;
  1312. if (!IsPredefinedType(method.DeclaringType))
  1313. throw ParseError(errorPos, Res.MethodsAreInaccessible, GetTypeName(method.DeclaringType));
  1314. if (method.ReturnType == typeof(void))
  1315. throw ParseError(errorPos, Res.MethodIsVoid,
  1316. id, GetTypeName(method.DeclaringType));
  1317. return Expression.Call(instance, (MethodInfo)method, args);
  1318. default:
  1319. throw ParseError(errorPos, Res.AmbiguousMethodInvocation,
  1320. id, GetTypeName(type));
  1321. }
  1322. }
  1323. else
  1324. {
  1325. MemberInfo member = FindPropertyOrField(type, id, instance == null);
  1326. if (member == null)
  1327. throw ParseError(errorPos, Res.UnknownPropertyOrField,
  1328. id, GetTypeName(type));
  1329. return member is PropertyInfo ?
  1330. Expression.Property(instance, (PropertyInfo)member) :
  1331. Expression.Field(instance, (FieldInfo)member);
  1332. }
  1333. }
  1334.  
  1335. static Type FindGenericType(Type generic, Type type)
  1336. {
  1337. while (type != null && type != typeof(object))
  1338. {
  1339. if (type.IsGenericType && type.GetGenericTypeDefinition() == generic) return type;
  1340. if (generic.IsInterface)
  1341. {
  1342. foreach (Type intfType in type.GetInterfaces())
  1343. {
  1344. Type found = FindGenericType(generic, intfType);
  1345. if (found != null) return found;
  1346. }
  1347. }
  1348. type = type.BaseType;
  1349. }
  1350. return null;
  1351. }
  1352.  
  1353. Expression ParseAggregate(Expression instance, Type elementType, string methodName, int errorPos)
  1354. {
  1355. ParameterExpression outerIt = it;
  1356. ParameterExpression innerIt = Expression.Parameter(elementType, "");
  1357. it = innerIt;
  1358. Expression[] args = ParseArgumentList();
  1359. it = outerIt;
  1360. MethodBase signature;
  1361. if (FindMethod(typeof(IEnumerableSignatures), methodName, false, args, out signature) != )
  1362. throw ParseError(errorPos, Res.NoApplicableAggregate, methodName);
  1363. Type[] typeArgs;
  1364. if (signature.Name == "Min" || signature.Name == "Max")
  1365. {
  1366. typeArgs = new Type[] { elementType, args[].Type };
  1367. }
  1368. else
  1369. {
  1370. typeArgs = new Type[] { elementType };
  1371. }
  1372. if (args.Length == )
  1373. {
  1374. args = new Expression[] { instance };
  1375. }
  1376. else
  1377. {
  1378. args = new Expression[] { instance, Expression.Lambda(args[], innerIt) };
  1379. }
  1380. return Expression.Call(typeof(Enumerable), signature.Name, typeArgs, args);
  1381. }
  1382.  
  1383. Expression[] ParseArgumentList()
  1384. {
  1385. ValidateToken(TokenId.OpenParen, Res.OpenParenExpected);
  1386. NextToken();
  1387. Expression[] args = token.id != TokenId.CloseParen ? ParseArguments() : new Expression[];
  1388. ValidateToken(TokenId.CloseParen, Res.CloseParenOrCommaExpected);
  1389. NextToken();
  1390. return args;
  1391. }
  1392.  
  1393. Expression[] ParseArguments()
  1394. {
  1395. List<Expression> argList = new List<Expression>();
  1396. while (true)
  1397. {
  1398. argList.Add(ParseExpression());
  1399. if (token.id != TokenId.Comma) break;
  1400. NextToken();
  1401. }
  1402. return argList.ToArray();
  1403. }
  1404.  
  1405. Expression ParseElementAccess(Expression expr)
  1406. {
  1407. int errorPos = token.pos;
  1408. ValidateToken(TokenId.OpenBracket, Res.OpenParenExpected);
  1409. NextToken();
  1410. Expression[] args = ParseArguments();
  1411. ValidateToken(TokenId.CloseBracket, Res.CloseBracketOrCommaExpected);
  1412. NextToken();
  1413. if (expr.Type.IsArray)
  1414. {
  1415. if (expr.Type.GetArrayRank() != || args.Length != )
  1416. throw ParseError(errorPos, Res.CannotIndexMultiDimArray);
  1417. Expression index = PromoteExpression(args[], typeof(int), true);
  1418. if (index == null)
  1419. throw ParseError(errorPos, Res.InvalidIndex);
  1420. return Expression.ArrayIndex(expr, index);
  1421. }
  1422. else
  1423. {
  1424. MethodBase mb;
  1425. switch (FindIndexer(expr.Type, args, out mb))
  1426. {
  1427. case :
  1428. throw ParseError(errorPos, Res.NoApplicableIndexer,
  1429. GetTypeName(expr.Type));
  1430. case :
  1431. return Expression.Call(expr, (MethodInfo)mb, args);
  1432. default:
  1433. throw ParseError(errorPos, Res.AmbiguousIndexerInvocation,
  1434. GetTypeName(expr.Type));
  1435. }
  1436. }
  1437. }
  1438.  
  1439. static bool IsPredefinedType(Type type)
  1440. {
  1441. foreach (Type t in predefinedTypes) if (t == type) return true;
  1442. return false;
  1443. }
  1444.  
  1445. static bool IsNullableType(Type type)
  1446. {
  1447. return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
  1448. }
  1449.  
  1450. static Type GetNonNullableType(Type type)
  1451. {
  1452. return IsNullableType(type) ? type.GetGenericArguments()[] : type;
  1453. }
  1454.  
  1455. static string GetTypeName(Type type)
  1456. {
  1457. Type baseType = GetNonNullableType(type);
  1458. string s = baseType.Name;
  1459. if (type != baseType) s += '?';
  1460. return s;
  1461. }
  1462.  
  1463. static bool IsNumericType(Type type)
  1464. {
  1465. return GetNumericTypeKind(type) != ;
  1466. }
  1467.  
  1468. static bool IsSignedIntegralType(Type type)
  1469. {
  1470. return GetNumericTypeKind(type) == ;
  1471. }
  1472.  
  1473. static bool IsUnsignedIntegralType(Type type)
  1474. {
  1475. return GetNumericTypeKind(type) == ;
  1476. }
  1477.  
  1478. static int GetNumericTypeKind(Type type)
  1479. {
  1480. type = GetNonNullableType(type);
  1481. if (type.IsEnum) return ;
  1482. switch (Type.GetTypeCode(type))
  1483. {
  1484. case TypeCode.Char:
  1485. case TypeCode.Single:
  1486. case TypeCode.Double:
  1487. case TypeCode.Decimal:
  1488. return ;
  1489. case TypeCode.SByte:
  1490. case TypeCode.Int16:
  1491. case TypeCode.Int32:
  1492. case TypeCode.Int64:
  1493. return ;
  1494. case TypeCode.Byte:
  1495. case TypeCode.UInt16:
  1496. case TypeCode.UInt32:
  1497. case TypeCode.UInt64:
  1498. return ;
  1499. default:
  1500. return ;
  1501. }
  1502. }
  1503.  
  1504. static bool IsEnumType(Type type)
  1505. {
  1506. return GetNonNullableType(type).IsEnum;
  1507. }
  1508.  
  1509. void CheckAndPromoteOperand(Type signatures, string opName, ref Expression expr, int errorPos)
  1510. {
  1511. Expression[] args = new Expression[] { expr };
  1512. MethodBase method;
  1513. if (FindMethod(signatures, "F", false, args, out method) != )
  1514. throw ParseError(errorPos, Res.IncompatibleOperand,
  1515. opName, GetTypeName(args[].Type));
  1516. expr = args[];
  1517. }
  1518.  
  1519. void CheckAndPromoteOperands(Type signatures, string opName, ref Expression left, ref Expression right, int errorPos)
  1520. {
  1521. Expression[] args = new Expression[] { left, right };
  1522. MethodBase method;
  1523. if (FindMethod(signatures, "F", false, args, out method) != )
  1524. throw IncompatibleOperandsError(opName, left, right, errorPos);
  1525. left = args[];
  1526. right = args[];
  1527. }
  1528.  
  1529. Exception IncompatibleOperandsError(string opName, Expression left, Expression right, int pos)
  1530. {
  1531. return ParseError(pos, Res.IncompatibleOperands,
  1532. opName, GetTypeName(left.Type), GetTypeName(right.Type));
  1533. }
  1534.  
  1535. MemberInfo FindPropertyOrField(Type type, string memberName, bool staticAccess)
  1536. {
  1537. BindingFlags flags = BindingFlags.Public | BindingFlags.DeclaredOnly |
  1538. (staticAccess ? BindingFlags.Static : BindingFlags.Instance);
  1539. foreach (Type t in SelfAndBaseTypes(type))
  1540. {
  1541. MemberInfo[] members = t.FindMembers(MemberTypes.Property | MemberTypes.Field,
  1542. flags, Type.FilterNameIgnoreCase, memberName);
  1543. if (members.Length != ) return members[];
  1544. }
  1545. return null;
  1546. }
  1547.  
  1548. int FindMethod(Type type, string methodName, bool staticAccess, Expression[] args, out MethodBase method)
  1549. {
  1550. BindingFlags flags = BindingFlags.Public | BindingFlags.DeclaredOnly |
  1551. (staticAccess ? BindingFlags.Static : BindingFlags.Instance);
  1552. foreach (Type t in SelfAndBaseTypes(type))
  1553. {
  1554. MemberInfo[] members = t.FindMembers(MemberTypes.Method,
  1555. flags, Type.FilterNameIgnoreCase, methodName);
  1556. int count = FindBestMethod(members.Cast<MethodBase>(), args, out method);
  1557. if (count != ) return count;
  1558. }
  1559. method = null;
  1560. return ;
  1561. }
  1562.  
  1563. int FindIndexer(Type type, Expression[] args, out MethodBase method)
  1564. {
  1565. foreach (Type t in SelfAndBaseTypes(type))
  1566. {
  1567. MemberInfo[] members = t.GetDefaultMembers();
  1568. if (members.Length != )
  1569. {
  1570. IEnumerable<MethodBase> methods = members.
  1571. OfType<PropertyInfo>().
  1572. Select(p => (MethodBase)p.GetGetMethod()).
  1573. Where(m => m != null);
  1574. int count = FindBestMethod(methods, args, out method);
  1575. if (count != ) return count;
  1576. }
  1577. }
  1578. method = null;
  1579. return ;
  1580. }
  1581.  
  1582. static IEnumerable<Type> SelfAndBaseTypes(Type type)
  1583. {
  1584. if (type.IsInterface)
  1585. {
  1586. List<Type> types = new List<Type>();
  1587. AddInterface(types, type);
  1588. return types;
  1589. }
  1590. return SelfAndBaseClasses(type);
  1591. }
  1592.  
  1593. static IEnumerable<Type> SelfAndBaseClasses(Type type)
  1594. {
  1595. while (type != null)
  1596. {
  1597. yield return type;
  1598. type = type.BaseType;
  1599. }
  1600. }
  1601.  
  1602. static void AddInterface(List<Type> types, Type type)
  1603. {
  1604. if (!types.Contains(type))
  1605. {
  1606. types.Add(type);
  1607. foreach (Type t in type.GetInterfaces()) AddInterface(types, t);
  1608. }
  1609. }
  1610.  
  1611. class MethodData
  1612. {
  1613. public MethodBase MethodBase;
  1614. public ParameterInfo[] Parameters;
  1615. public Expression[] Args;
  1616. }
  1617.  
  1618. int FindBestMethod(IEnumerable<MethodBase> methods, Expression[] args, out MethodBase method)
  1619. {
  1620. MethodData[] applicable = methods.
  1621. Select(m => new MethodData { MethodBase = m, Parameters = m.GetParameters() }).
  1622. Where(m => IsApplicable(m, args)).
  1623. ToArray();
  1624. if (applicable.Length > )
  1625. {
  1626. applicable = applicable.
  1627. Where(m => applicable.All(n => m == n || IsBetterThan(args, m, n))).
  1628. ToArray();
  1629. }
  1630. if (applicable.Length == )
  1631. {
  1632. MethodData md = applicable[];
  1633. for (int i = ; i < args.Length; i++) args[i] = md.Args[i];
  1634. method = md.MethodBase;
  1635. }
  1636. else
  1637. {
  1638. method = null;
  1639. }
  1640. return applicable.Length;
  1641. }
  1642.  
  1643. bool IsApplicable(MethodData method, Expression[] args)
  1644. {
  1645. if (method.Parameters.Length != args.Length) return false;
  1646. Expression[] promotedArgs = new Expression[args.Length];
  1647. for (int i = ; i < args.Length; i++)
  1648. {
  1649. ParameterInfo pi = method.Parameters[i];
  1650. if (pi.IsOut) return false;
  1651. Expression promoted = PromoteExpression(args[i], pi.ParameterType, false);
  1652. if (promoted == null) return false;
  1653. promotedArgs[i] = promoted;
  1654. }
  1655. method.Args = promotedArgs;
  1656. return true;
  1657. }
  1658.  
  1659. Expression PromoteExpression(Expression expr, Type type, bool exact)
  1660. {
  1661. if (expr.Type == type) return expr;
  1662. if (expr is ConstantExpression)
  1663. {
  1664. ConstantExpression ce = (ConstantExpression)expr;
  1665. if (ce == nullLiteral)
  1666. {
  1667. if (!type.IsValueType || IsNullableType(type))
  1668. return Expression.Constant(null, type);
  1669. }
  1670. else
  1671. {
  1672. string text;
  1673. if (literals.TryGetValue(ce, out text))
  1674. {
  1675. Type target = GetNonNullableType(type);
  1676. Object value = null;
  1677. switch (Type.GetTypeCode(ce.Type))
  1678. {
  1679. case TypeCode.Int32:
  1680. case TypeCode.UInt32:
  1681. case TypeCode.Int64:
  1682. case TypeCode.UInt64:
  1683. value = ParseNumber(text, target);
  1684. break;
  1685. case TypeCode.Double:
  1686. if (target == typeof(decimal)) value = ParseNumber(text, target);
  1687. break;
  1688. case TypeCode.String:
  1689. value = ParseEnum(text, target);
  1690. break;
  1691. }
  1692. if (value != null)
  1693. return Expression.Constant(value, type);
  1694. }
  1695. }
  1696. }
  1697. if (IsCompatibleWith(expr.Type, type))
  1698. {
  1699. if (type.IsValueType || exact) return Expression.Convert(expr, type);
  1700. return expr;
  1701. }
  1702. return null;
  1703. }
  1704.  
  1705. static object ParseNumber(string text, Type type)
  1706. {
  1707. switch (Type.GetTypeCode(GetNonNullableType(type)))
  1708. {
  1709. case TypeCode.SByte:
  1710. sbyte sb;
  1711. if (sbyte.TryParse(text, out sb)) return sb;
  1712. break;
  1713. case TypeCode.Byte:
  1714. byte b;
  1715. if (byte.TryParse(text, out b)) return b;
  1716. break;
  1717. case TypeCode.Int16:
  1718. short s;
  1719. if (short.TryParse(text, out s)) return s;
  1720. break;
  1721. case TypeCode.UInt16:
  1722. ushort us;
  1723. if (ushort.TryParse(text, out us)) return us;
  1724. break;
  1725. case TypeCode.Int32:
  1726. int i;
  1727. if (int.TryParse(text, out i)) return i;
  1728. break;
  1729. case TypeCode.UInt32:
  1730. uint ui;
  1731. if (uint.TryParse(text, out ui)) return ui;
  1732. break;
  1733. case TypeCode.Int64:
  1734. long l;
  1735. if (long.TryParse(text, out l)) return l;
  1736. break;
  1737. case TypeCode.UInt64:
  1738. ulong ul;
  1739. if (ulong.TryParse(text, out ul)) return ul;
  1740. break;
  1741. case TypeCode.Single:
  1742. float f;
  1743. if (float.TryParse(text, out f)) return f;
  1744. break;
  1745. case TypeCode.Double:
  1746. double d;
  1747. if (double.TryParse(text, out d)) return d;
  1748. break;
  1749. case TypeCode.Decimal:
  1750. decimal e;
  1751. if (decimal.TryParse(text, out e)) return e;
  1752. break;
  1753. }
  1754. return null;
  1755. }
  1756.  
  1757. static object ParseEnum(string name, Type type)
  1758. {
  1759. if (type.IsEnum)
  1760. {
  1761. MemberInfo[] memberInfos = type.FindMembers(MemberTypes.Field,
  1762. BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Static,
  1763. Type.FilterNameIgnoreCase, name);
  1764. if (memberInfos.Length != ) return ((FieldInfo)memberInfos[]).GetValue(null);
  1765. }
  1766. return null;
  1767. }
  1768.  
  1769. static bool IsCompatibleWith(Type source, Type target)
  1770. {
  1771. if (source == target) return true;
  1772. if (!target.IsValueType) return target.IsAssignableFrom(source);
  1773. Type st = GetNonNullableType(source);
  1774. Type tt = GetNonNullableType(target);
  1775. if (st != source && tt == target) return false;
  1776. TypeCode sc = st.IsEnum ? TypeCode.Object : Type.GetTypeCode(st);
  1777. TypeCode tc = tt.IsEnum ? TypeCode.Object : Type.GetTypeCode(tt);
  1778. switch (sc)
  1779. {
  1780. case TypeCode.SByte:
  1781. switch (tc)
  1782. {
  1783. case TypeCode.SByte:
  1784. case TypeCode.Int16:
  1785. case TypeCode.Int32:
  1786. case TypeCode.Int64:
  1787. case TypeCode.Single:
  1788. case TypeCode.Double:
  1789. case TypeCode.Decimal:
  1790. return true;
  1791. }
  1792. break;
  1793. case TypeCode.Byte:
  1794. switch (tc)
  1795. {
  1796. case TypeCode.Byte:
  1797. case TypeCode.Int16:
  1798. case TypeCode.UInt16:
  1799. case TypeCode.Int32:
  1800. case TypeCode.UInt32:
  1801. case TypeCode.Int64:
  1802. case TypeCode.UInt64:
  1803. case TypeCode.Single:
  1804. case TypeCode.Double:
  1805. case TypeCode.Decimal:
  1806. return true;
  1807. }
  1808. break;
  1809. case TypeCode.Int16:
  1810. switch (tc)
  1811. {
  1812. case TypeCode.Int16:
  1813. case TypeCode.Int32:
  1814. case TypeCode.Int64:
  1815. case TypeCode.Single:
  1816. case TypeCode.Double:
  1817. case TypeCode.Decimal:
  1818. return true;
  1819. }
  1820. break;
  1821. case TypeCode.UInt16:
  1822. switch (tc)
  1823. {
  1824. case TypeCode.UInt16:
  1825. case TypeCode.Int32:
  1826. case TypeCode.UInt32:
  1827. case TypeCode.Int64:
  1828. case TypeCode.UInt64:
  1829. case TypeCode.Single:
  1830. case TypeCode.Double:
  1831. case TypeCode.Decimal:
  1832. return true;
  1833. }
  1834. break;
  1835. case TypeCode.Int32:
  1836. switch (tc)
  1837. {
  1838. case TypeCode.Int32:
  1839. case TypeCode.Int64:
  1840. case TypeCode.Single:
  1841. case TypeCode.Double:
  1842. case TypeCode.Decimal:
  1843. return true;
  1844. }
  1845. break;
  1846. case TypeCode.UInt32:
  1847. switch (tc)
  1848. {
  1849. case TypeCode.UInt32:
  1850. case TypeCode.Int64:
  1851. case TypeCode.UInt64:
  1852. case TypeCode.Single:
  1853. case TypeCode.Double:
  1854. case TypeCode.Decimal:
  1855. return true;
  1856. }
  1857. break;
  1858. case TypeCode.Int64:
  1859. switch (tc)
  1860. {
  1861. case TypeCode.Int64:
  1862. case TypeCode.Single:
  1863. case TypeCode.Double:
  1864. case TypeCode.Decimal:
  1865. return true;
  1866. }
  1867. break;
  1868. case TypeCode.UInt64:
  1869. switch (tc)
  1870. {
  1871. case TypeCode.UInt64:
  1872. case TypeCode.Single:
  1873. case TypeCode.Double:
  1874. case TypeCode.Decimal:
  1875. return true;
  1876. }
  1877. break;
  1878. case TypeCode.Single:
  1879. switch (tc)
  1880. {
  1881. case TypeCode.Single:
  1882. case TypeCode.Double:
  1883. return true;
  1884. }
  1885. break;
  1886. default:
  1887. if (st == tt) return true;
  1888. break;
  1889. }
  1890. return false;
  1891. }
  1892.  
  1893. static bool IsBetterThan(Expression[] args, MethodData m1, MethodData m2)
  1894. {
  1895. bool better = false;
  1896. for (int i = ; i < args.Length; i++)
  1897. {
  1898. int c = CompareConversions(args[i].Type,
  1899. m1.Parameters[i].ParameterType,
  1900. m2.Parameters[i].ParameterType);
  1901. if (c < ) return false;
  1902. if (c > ) better = true;
  1903. }
  1904. return better;
  1905. }
  1906.  
  1907. // Return 1 if s -> t1 is a better conversion than s -> t2
  1908. // Return -1 if s -> t2 is a better conversion than s -> t1
  1909. // Return 0 if neither conversion is better
  1910. static int CompareConversions(Type s, Type t1, Type t2)
  1911. {
  1912. if (t1 == t2) return ;
  1913. if (s == t1) return ;
  1914. if (s == t2) return -;
  1915. bool t1t2 = IsCompatibleWith(t1, t2);
  1916. bool t2t1 = IsCompatibleWith(t2, t1);
  1917. if (t1t2 && !t2t1) return ;
  1918. if (t2t1 && !t1t2) return -;
  1919. if (IsSignedIntegralType(t1) && IsUnsignedIntegralType(t2)) return ;
  1920. if (IsSignedIntegralType(t2) && IsUnsignedIntegralType(t1)) return -;
  1921. return ;
  1922. }
  1923.  
  1924. Expression GenerateEqual(Expression left, Expression right)
  1925. {
  1926. return Expression.Equal(left, right);
  1927. }
  1928.  
  1929. Expression GenerateNotEqual(Expression left, Expression right)
  1930. {
  1931. return Expression.NotEqual(left, right);
  1932. }
  1933.  
  1934. Expression GenerateGreaterThan(Expression left, Expression right)
  1935. {
  1936. if (left.Type == typeof(string))
  1937. {
  1938. return Expression.GreaterThan(
  1939. GenerateStaticMethodCall("Compare", left, right),
  1940. Expression.Constant()
  1941. );
  1942. }
  1943. return Expression.GreaterThan(left, right);
  1944. }
  1945.  
  1946. Expression GenerateGreaterThanEqual(Expression left, Expression right)
  1947. {
  1948. if (left.Type == typeof(string))
  1949. {
  1950. return Expression.GreaterThanOrEqual(
  1951. GenerateStaticMethodCall("Compare", left, right),
  1952. Expression.Constant()
  1953. );
  1954. }
  1955. return Expression.GreaterThanOrEqual(left, right);
  1956. }
  1957.  
  1958. Expression GenerateLessThan(Expression left, Expression right)
  1959. {
  1960. if (left.Type == typeof(string))
  1961. {
  1962. return Expression.LessThan(
  1963. GenerateStaticMethodCall("Compare", left, right),
  1964. Expression.Constant()
  1965. );
  1966. }
  1967. return Expression.LessThan(left, right);
  1968. }
  1969.  
  1970. Expression GenerateLessThanEqual(Expression left, Expression right)
  1971. {
  1972. if (left.Type == typeof(string))
  1973. {
  1974. return Expression.LessThanOrEqual(
  1975. GenerateStaticMethodCall("Compare", left, right),
  1976. Expression.Constant()
  1977. );
  1978. }
  1979. return Expression.LessThanOrEqual(left, right);
  1980. }
  1981.  
  1982. Expression GenerateAdd(Expression left, Expression right)
  1983. {
  1984. if (left.Type == typeof(string) && right.Type == typeof(string))
  1985. {
  1986. return GenerateStaticMethodCall("Concat", left, right);
  1987. }
  1988. return Expression.Add(left, right);
  1989. }
  1990.  
  1991. Expression GenerateSubtract(Expression left, Expression right)
  1992. {
  1993. return Expression.Subtract(left, right);
  1994. }
  1995.  
  1996. Expression GenerateStringConcat(Expression left, Expression right)
  1997. {
  1998. return Expression.Call(
  1999. null,
  2000. typeof(string).GetMethod("Concat", new[] { typeof(object), typeof(object) }),
  2001. new[] { left, right });
  2002. }
  2003.  
  2004. MethodInfo GetStaticMethod(string methodName, Expression left, Expression right)
  2005. {
  2006. return left.Type.GetMethod(methodName, new[] { left.Type, right.Type });
  2007. }
  2008.  
  2009. Expression GenerateStaticMethodCall(string methodName, Expression left, Expression right)
  2010. {
  2011. return Expression.Call(null, GetStaticMethod(methodName, left, right), new[] { left, right });
  2012. }
  2013.  
  2014. void SetTextPos(int pos)
  2015. {
  2016. textPos = pos;
  2017. ch = textPos < textLen ? text[textPos] : '\0';
  2018. }
  2019.  
  2020. void NextChar()
  2021. {
  2022. if (textPos < textLen) textPos++;
  2023. ch = textPos < textLen ? text[textPos] : '\0';
  2024. }
  2025.  
  2026. void NextToken()
  2027. {
  2028. while (Char.IsWhiteSpace(ch)) NextChar();
  2029. TokenId t;
  2030. int tokenPos = textPos;
  2031. switch (ch)
  2032. {
  2033. case '!':
  2034. NextChar();
  2035. if (ch == '=')
  2036. {
  2037. NextChar();
  2038. t = TokenId.ExclamationEqual;
  2039. }
  2040. else
  2041. {
  2042. t = TokenId.Exclamation;
  2043. }
  2044. break;
  2045. case '%':
  2046. NextChar();
  2047. t = TokenId.Percent;
  2048. break;
  2049. case '&':
  2050. NextChar();
  2051. if (ch == '&')
  2052. {
  2053. NextChar();
  2054. t = TokenId.DoubleAmphersand;
  2055. }
  2056. else
  2057. {
  2058. t = TokenId.Amphersand;
  2059. }
  2060. break;
  2061. case '(':
  2062. NextChar();
  2063. t = TokenId.OpenParen;
  2064. break;
  2065. case ')':
  2066. NextChar();
  2067. t = TokenId.CloseParen;
  2068. break;
  2069. case '*':
  2070. NextChar();
  2071. t = TokenId.Asterisk;
  2072. break;
  2073. case '+':
  2074. NextChar();
  2075. t = TokenId.Plus;
  2076. break;
  2077. case ',':
  2078. NextChar();
  2079. t = TokenId.Comma;
  2080. break;
  2081. case '-':
  2082. NextChar();
  2083. t = TokenId.Minus;
  2084. break;
  2085. case '.':
  2086. NextChar();
  2087. t = TokenId.Dot;
  2088. break;
  2089. case '/':
  2090. NextChar();
  2091. t = TokenId.Slash;
  2092. break;
  2093. case ':':
  2094. NextChar();
  2095. t = TokenId.Colon;
  2096. break;
  2097. case '<':
  2098. NextChar();
  2099. if (ch == '=')
  2100. {
  2101. NextChar();
  2102. t = TokenId.LessThanEqual;
  2103. }
  2104. else if (ch == '>')
  2105. {
  2106. NextChar();
  2107. t = TokenId.LessGreater;
  2108. }
  2109. else
  2110. {
  2111. t = TokenId.LessThan;
  2112. }
  2113. break;
  2114. case '=':
  2115. NextChar();
  2116. if (ch == '=')
  2117. {
  2118. NextChar();
  2119. t = TokenId.DoubleEqual;
  2120. }
  2121. else
  2122. {
  2123. t = TokenId.Equal;
  2124. }
  2125. break;
  2126. case '>':
  2127. NextChar();
  2128. if (ch == '=')
  2129. {
  2130. NextChar();
  2131. t = TokenId.GreaterThanEqual;
  2132. }
  2133. else
  2134. {
  2135. t = TokenId.GreaterThan;
  2136. }
  2137. break;
  2138. case '?':
  2139. NextChar();
  2140. t = TokenId.Question;
  2141. break;
  2142. case '[':
  2143. NextChar();
  2144. t = TokenId.OpenBracket;
  2145. break;
  2146. case ']':
  2147. NextChar();
  2148. t = TokenId.CloseBracket;
  2149. break;
  2150. case '|':
  2151. NextChar();
  2152. if (ch == '|')
  2153. {
  2154. NextChar();
  2155. t = TokenId.DoubleBar;
  2156. }
  2157. else
  2158. {
  2159. t = TokenId.Bar;
  2160. }
  2161. break;
  2162. case '"':
  2163. case '\'':
  2164. char quote = ch;
  2165. do
  2166. {
  2167. NextChar();
  2168. while (textPos < textLen && ch != quote) NextChar();
  2169. if (textPos == textLen)
  2170. throw ParseError(textPos, Res.UnterminatedStringLiteral);
  2171. NextChar();
  2172. } while (ch == quote);
  2173. t = TokenId.StringLiteral;
  2174. break;
  2175. default:
  2176. if (Char.IsLetter(ch) || ch == '@' || ch == '_')
  2177. {
  2178. do
  2179. {
  2180. NextChar();
  2181. } while (Char.IsLetterOrDigit(ch) || ch == '_');
  2182. t = TokenId.Identifier;
  2183. break;
  2184. }
  2185. if (Char.IsDigit(ch))
  2186. {
  2187. t = TokenId.IntegerLiteral;
  2188. do
  2189. {
  2190. NextChar();
  2191. } while (Char.IsDigit(ch));
  2192. if (ch == '.')
  2193. {
  2194. t = TokenId.RealLiteral;
  2195. NextChar();
  2196. ValidateDigit();
  2197. do
  2198. {
  2199. NextChar();
  2200. } while (Char.IsDigit(ch));
  2201. }
  2202. if (ch == 'E' || ch == 'e')
  2203. {
  2204. t = TokenId.RealLiteral;
  2205. NextChar();
  2206. if (ch == '+' || ch == '-') NextChar();
  2207. ValidateDigit();
  2208. do
  2209. {
  2210. NextChar();
  2211. } while (Char.IsDigit(ch));
  2212. }
  2213. if (ch == 'F' || ch == 'f') NextChar();
  2214. break;
  2215. }
  2216. if (textPos == textLen)
  2217. {
  2218. t = TokenId.End;
  2219. break;
  2220. }
  2221. throw ParseError(textPos, Res.InvalidCharacter, ch);
  2222. }
  2223. token.id = t;
  2224. token.text = text.Substring(tokenPos, textPos - tokenPos);
  2225. token.pos = tokenPos;
  2226. }
  2227.  
  2228. bool TokenIdentifierIs(string id)
  2229. {
  2230. return token.id == TokenId.Identifier && String.Equals(id, token.text, StringComparison.OrdinalIgnoreCase);
  2231. }
  2232.  
  2233. string GetIdentifier()
  2234. {
  2235. ValidateToken(TokenId.Identifier, Res.IdentifierExpected);
  2236. string id = token.text;
  2237. if (id.Length > && id[] == '@') id = id.Substring();
  2238. return id;
  2239. }
  2240.  
  2241. void ValidateDigit()
  2242. {
  2243. if (!Char.IsDigit(ch)) throw ParseError(textPos, Res.DigitExpected);
  2244. }
  2245.  
  2246. void ValidateToken(TokenId t, string errorMessage)
  2247. {
  2248. if (token.id != t) throw ParseError(errorMessage);
  2249. }
  2250.  
  2251. void ValidateToken(TokenId t)
  2252. {
  2253. if (token.id != t) throw ParseError(Res.SyntaxError);
  2254. }
  2255.  
  2256. Exception ParseError(string format, params object[] args)
  2257. {
  2258. return ParseError(token.pos, format, args);
  2259. }
  2260.  
  2261. Exception ParseError(int pos, string format, params object[] args)
  2262. {
  2263. return new ParseException(string.Format(System.Globalization.CultureInfo.CurrentCulture, format, args), pos);
  2264. }
  2265.  
  2266. static Dictionary<string, object> CreateKeywords()
  2267. {
  2268. Dictionary<string, object> d = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
  2269. d.Add("true", trueLiteral);
  2270. d.Add("false", falseLiteral);
  2271. d.Add("null", nullLiteral);
  2272. d.Add(keywordIt, keywordIt);
  2273. d.Add(keywordIif, keywordIif);
  2274. d.Add(keywordNew, keywordNew);
  2275. foreach (Type type in predefinedTypes) d.Add(type.Name, type);
  2276. return d;
  2277. }
  2278. }
  2279.  
  2280. static class Res
  2281. {
  2282. public const string DuplicateIdentifier = "The identifier '{0}' was defined more than once";
  2283. public const string ExpressionTypeMismatch = "Expression of type '{0}' expected";
  2284. public const string ExpressionExpected = "Expression expected";
  2285. public const string InvalidCharacterLiteral = "Character literal must contain exactly one character";
  2286. public const string InvalidIntegerLiteral = "Invalid integer literal '{0}'";
  2287. public const string InvalidRealLiteral = "Invalid real literal '{0}'";
  2288. public const string UnknownIdentifier = "Unknown identifier '{0}'";
  2289. public const string NoItInScope = "No 'it' is in scope";
  2290. public const string IifRequiresThreeArgs = "The 'iif' function requires three arguments";
  2291. public const string FirstExprMustBeBool = "The first expression must be of type 'Boolean'";
  2292. public const string BothTypesConvertToOther = "Both of the types '{0}' and '{1}' convert to the other";
  2293. public const string NeitherTypeConvertsToOther = "Neither of the types '{0}' and '{1}' converts to the other";
  2294. public const string MissingAsClause = "Expression is missing an 'as' clause";
  2295. public const string ArgsIncompatibleWithLambda = "Argument list incompatible with lambda expression";
  2296. public const string TypeHasNoNullableForm = "Type '{0}' has no nullable form";
  2297. public const string NoMatchingConstructor = "No matching constructor in type '{0}'";
  2298. public const string AmbiguousConstructorInvocation = "Ambiguous invocation of '{0}' constructor";
  2299. public const string CannotConvertValue = "A value of type '{0}' cannot be converted to type '{1}'";
  2300. public const string NoApplicableMethod = "No applicable method '{0}' exists in type '{1}'";
  2301. public const string MethodsAreInaccessible = "Methods on type '{0}' are not accessible";
  2302. public const string MethodIsVoid = "Method '{0}' in type '{1}' does not return a value";
  2303. public const string AmbiguousMethodInvocation = "Ambiguous invocation of method '{0}' in type '{1}'";
  2304. public const string UnknownPropertyOrField = "No property or field '{0}' exists in type '{1}'";
  2305. public const string NoApplicableAggregate = "No applicable aggregate method '{0}' exists";
  2306. public const string CannotIndexMultiDimArray = "Indexing of multi-dimensional arrays is not supported";
  2307. public const string InvalidIndex = "Array index must be an integer expression";
  2308. public const string NoApplicableIndexer = "No applicable indexer exists in type '{0}'";
  2309. public const string AmbiguousIndexerInvocation = "Ambiguous invocation of indexer in type '{0}'";
  2310. public const string IncompatibleOperand = "Operator '{0}' incompatible with operand type '{1}'";
  2311. public const string IncompatibleOperands = "Operator '{0}' incompatible with operand types '{1}' and '{2}'";
  2312. public const string UnterminatedStringLiteral = "Unterminated string literal";
  2313. public const string InvalidCharacter = "Syntax error '{0}'";
  2314. public const string DigitExpected = "Digit expected";
  2315. public const string SyntaxError = "Syntax error";
  2316. public const string TokenExpected = "{0} expected";
  2317. public const string ParseExceptionFormat = "{0} (at index {1})";
  2318. public const string ColonExpected = "':' expected";
  2319. public const string OpenParenExpected = "'(' expected";
  2320. public const string CloseParenOrOperatorExpected = "')' or operator expected";
  2321. public const string CloseParenOrCommaExpected = "')' or ',' expected";
  2322. public const string DotOrOpenParenExpected = "'.' or '(' expected";
  2323. public const string OpenBracketExpected = "'[' expected";
  2324. public const string CloseBracketOrCommaExpected = "']' or ',' expected";
  2325. public const string IdentifierExpected = "Identifier expected";
  2326. }

此时,我们需要将我们的实体和数据库字段映射对应起来,新建一个ImageMap类代码如下:

  1. public class ImageMap : EntityTypeConfiguration<ImageModel>
  2. {
  3. public ImageMap()
  4. {
  5. // Primary Key
  6. this.HasKey(t => t.ID);
  7.  
  8. // Properties
  9. this.Property(t => t.IDProofFront)
  10. .HasMaxLength();
  11.  
  12. this.Property(t => t.IDProofBack)
  13. .HasMaxLength();
  14.  
  15. // Table & Column Mappings
  16. this.ToTable("ImageModel");
  17. this.Property(t => t.ID).HasColumnName("ID");
  18. this.Property(t => t.IDProofFront).HasColumnName("IDProofFront");
  19. this.Property(t => t.IDProofBack).HasColumnName("IDProofBack");
  20. }
  21. }

其中ToTable就是指明数据库表名,

那么如何将上传的图片保存更新到数据库呢?

接下来我们新建一个接口类IResourcesImage 并继承操作基类 IRepository<ImageModel>

定义一个上传身份信息的规则如下:

  1. bool UpdateIDProof(string IDProofFront, string IDProofBack, int pId);

接下来我们新建一个ResourcesImage 实现上述接口。代码如下

  1. public ResourcesImage() { }
  2. /// <summary>
  3. /// 上传身份信息采用此种方式
  4. /// </summary>
  5. /// <param name="IDProofBack"></param>
  6. /// <param name="IDProofBack"></param>
  7. /// <param name="pId"></param>
  8. /// <returns></returns>
  9. public bool UpdateIDProof(string IDProofFront, string IDProofBack, int pId)
  10. {
  11. int flag = ;
  12.  
  13. if (IDProofFront != "" && IDProofFront != null)
  14. {
  15. flag = this.Update(m => m.ID == pId, u => new ImageModel { IDProofFront = IDProofFront });
  16. if (flag == )
  17. {
  18. if (IDProofBack != "" && IDProofBack != null)
  19. flag = this.Update(m => m.ID == pId, u => new ImageModel { IDProofBack = IDProofBack });
  20. }
  21. }
  22. else
  23. {
  24. if (IDProofBack != "" && IDProofBack != null)
  25. flag = this.Update(m => m.ID == pId, u => new ImageModel { IDProofBack = IDProofBack });
  26. }
  27. return flag == ? false : true;
  28. }

我们在中间层做一下这个操作:

  1. private readonly IResourcesImage _resourcesImage;
  2. public CodeBLL()
  3. {
  4. this._resourcesImage = new ResourcesImage();
  5. }
  6. /// <summary>
  7. /// 根据字段更新用户的文件资料信息
  8. /// </summary>
  9. /// <param name="fileNameField">字段</param>
  10. /// <param name="fileNameValue">字段值</param>
  11. /// <param name="pId"></param>
  12. /// <returns></returns>
  13. public bool UpdateFileName(string IDProofFront, string IDProofBack, int pId)
  14. {
  15. bool flag = false;
  16. flag = _resourcesImage.UpdateIDProof(IDProofFront, IDProofBack, pId);
  17. return flag;
  18. }

这样做其实并不科学,需要手动实例化这种仓储操作,科学的方式可以使用IOC(控制反转).

中间层做好之后,我们只需要在HomeController中调用此方法即可,代码如下:

至此,我们就实现了本地通过ftp方式上传图片代码,并将图片以相对路径保存在数据库中,数据库存放格式如下:

Demo下载

点我下载Demo

Git下载

C# ftp 图片上传多快好省的更多相关文章

  1. ftp服务器搭建(windows)+实现ftp图片上传对接

    ftp服务器搭建(windows): vsftpd简介: vsftpd是“very secure FTP daemon”的缩写,是一个完全免费的.开放源代码的ftp服务器软件. 下载地址: http: ...

  2. Yii 图片FTP批量上传 并生成缩略图

    图片批量上传,前台使用 uploadify.swf,这个就不介绍了.这里使用两个扩展,一个是FTP上传的扩展,还有一个是生成缩略图的扩展地址:http://www.yiiframework.com/e ...

  3. 前端nginx+Java后台ftp处理页面图片上传踩坑

    今天,将前端代码部署到服务器nginx上,在测试多图片上传时,报错413请求体空间太大,请求都没到后台,直接被nginx拦截,调整后又报错504. 整体而言,前端存在两处问题: 413 错误 :Req ...

  4. 链接ftp,把文件或图片上传到ftp指定的文件夹中

    /******************************************************************** *  * * Filename : .java * Auth ...

  5. 使用KindEditor完成图片上传(springmvc&fastdfs/springmvc&ftp)

    前端使用KindEditor,后台使用Springmvc 1 拷贝KindEditor相关文件到项目中 拷贝KindEditor相关文件到项目中 2 准备一个jsp页面 页面中我准备了一个超链接,点击 ...

  6. 根目录97 <input file>标签,把图片上传到服务器(跟增删改查一起实现)

    首先来个简单的html页面: enctype="multipart/form-data" encoding="multipart/form-data" acti ...

  7. 使用递归方法实现,向FTP服务器上传整个目录结构、从FTP服务器下载整个目录到本地的功能

    我最近由于在做一个关于FTP文件上传和下载的功能时候,发现Apache FTP jar包没有提供对整个目录结构的上传和下载功能,只能非目录类型的文件进行上传和下载操作,后来我查阅很多网上的实现方法,再 ...

  8. [Nginx 2] form表单提交,图片上传

    导读:昨晚恶补了一些Nginx服务器的东西,从整体上对Nginx有一个初步的了解.上午去找师哥问了问目前项目中的使用情况,然后就开始上传图片了.这里就简单总结整理一下今天的成果,以后接着提升.简单粗暴 ...

  9. bootstrap-fileinput多图片上传

    在页面写一个input框: <input id="subGraphAddress1" name="subGraphAddress" type=" ...

随机推荐

  1. openfire+smack 实现即时通讯基本框架

    smack jar下载地址 http://www.igniterealtime.org/downloads/download-landing.jsp?file=smack/smack_3_2_2.zi ...

  2. .bind.apply() 解决 new 操作符不能用与 apply 或 call 同时使用

    背景: 小明想要用数组的形式为 Cls.func 传入多个参数,他想到了以下的写法: var a = new Cls.func.apply(null, [1, 2, 3]); 然而浏览器却报错Cls. ...

  3. MongoDB副本集的常用操作及原理

    本文是对MongoDB副本集常用操作的一个汇总,同时也穿插着介绍了操作背后的原理及注意点. 结合之前的文章:MongoDB副本集的搭建,大家可以在较短的时间内熟悉MongoDB的搭建和管理. 下面的操 ...

  4. webstorm html碎片整理功能

    我们用字符串形式写html模板时,或者向某标签添加html内容时,如下,如果这个str更加的长,一旦里面少了一个单引号,少了一个加号,基本报错还看不懂,一脸懵逼... // 假定后台传给我们的数据为 ...

  5. bootstrap 获得轮播中的索引或当前活动的焦点对象

    今天用bootstrap做一个轮播,当轮播滚到每张图的时候,在页面下面就显示相对应的内容,那么问题来了:为了轮播图的可扩展性,我们肯定需要知道当前活动(显示图片)的索引号,查了bootstrap文档, ...

  6. 使用cl编译C/C++

    每次写程序都是用VS下打开的,而且有智能提示,经常很容易看到自己哪里写错了,其实想联系自己写代码的能力,不应该要这些的,纯粹的不要智能提示 所以自己想用轻量级的编辑器写,然后就用了notepad++( ...

  7. 如何用C#完成控制台日历?

    本题目的最终要就是根据用户输入的年和月在控制台输出单月的日历信息,附加范围年在1900-2100之间,月的范围在1-12之间,当用户输入不在范围时要给予错误信息提示:已知条件是1900年1月1日为星期 ...

  8. idea 控制台输出 中文乱码 解决方法

    使用intellij idea 14.1时,console 会输出中文乱码.下面分两种情况解决这种问题:一种是maven构建项目.一种是tomcat(不以maven构建)构建项目. 1.tomcat输 ...

  9. Aspose.Cells.dll操作execl

    附件:Aspose.Cells.dll 1.创建execl(不需要服务器或者客户端安装office) public void DCExexl(DataTable dt) {  Workbook wb ...

  10. JBoss快速入门知识

    1.下载地址: http://www.jboss.org/jbossas/downloads