看Interpolated Strings之前,让我们先看EF Core 2.0 的一个新的特性:String interpolation in FromSql and ExecuteSqlCommand

  1. var city = "London";
  2. using (var context = CreateContext())
  3. {
  4. context.Customers
  5. .FromSql($@"
  6. SELECT *
  7. FROM Customers
  8. WHERE City = {city}")
  9. .ToArray();
  10. }

SQL语句以参数化的方式执行,所以是防字符串注入的。

  1. @p0='London' (Size = 4000)
  2. SELECT *
  3. FROM Customers
  4. WHERE City = @p0

一直认为Interpolated Strings只是String.Format的语法糖,传给FromSql的方法只是一个普通的字符串,已经移除了花括号,并把变量替换成了对应的值。FromSql获取不到变量信息,怎么实现参数化查询的呢? OK,让我们从头看起吧。

什么是内插字符串 (Interpolated Strings)

内插字符串是C# 6.0 引入的新的语法,它允许在字符串中插入表达式。

  1. var name = "world";
  2. Console.WriteLine($"hello {name}");

这种方式相对与之前的string.Format或者string.Concat更容易书写,可读性更高。就这点,已经可以令大多数人满意了。事实上,它不仅仅是一个简单的字符串。

内插字符串 (Interpolated Strings) 是什么?

用代码来回答这个问题:

  1. var name = "world";
  2. string str1 = $"hello {name}"; //等于 var str1 = $"hello {name}";
  3. IFormattable str2 = $"hello {name}";
  4. FormattableString str3 = $"hello {name}";

可以看出,Interpolated Strings 可以隐式转换为3种形式。实际上式编译器默默的为我们做了转换:

  1. var name = "world";
  2. string str1 = string.Format("hello {0}",name); //等于 var str1 = $"hello {name}";
  3. IFormattable str2 = FormattableStringFactory.Create("hello {0}",name);
  4. FormattableString str3 = FormattableStringFactory.Create("hello {0}",name);
  • IFormattable 从.net Framwork 1 时代就有了,只有一个ToString方法,可以传入IFormatProvider 来控制字符串的格式化。今天的主角不是他。
  • FormattableString 伴随Interpolated Strings引入的新类。

FormattableString 是什么?

先看一段代码

  1. var name = "world";
  2. FormattableString fmtString = $"hello {name}";
  3. Console.WriteLine(fmtString.ArgumentCount); //1
  4. Console.WriteLine(fmtString.Format); //hello {0}
  5. foreach (var arg in fmtString.GetArguments())
  6. {
  7. Console.WriteLine(arg); //world
  8. Console.WriteLine(arg.GetType()); //System.String
  9. }

可以看出FormattableString保存了Interpolated Strings的所有信息,所以EF Core 2.0能够以参数化的方式来执行SQL了。

EF Core 中的注意事项

因为隐式转换的原因,在使用EF Core的FromSql 方法和 ExecuteSqlCommand方法时,需要特别小心。一不留神就会调入陷阱。

  1. var city = "London";
  2. using (var context = CreateContext())
  3. {
  4. //方法一,非参数化
  5. var sql = $" SELECT * FROM Customers WHERE City = {city}";
  6. context.Customers.FromSql(sql).ToArray();
  7. //方法二,参数化
  8. context.Customers.FromSql($" SELECT * FROM Customers WHERE City = {city}").ToArray();
  9. //方法三,参数化
  10. FormattableString fsql = $" SELECT * FROM Customers WHERE City = {city}";
  11. context.Customers.FromSql(fsql).ToArray();
  12. //方法四,非参数化
  13. var sql = " SELECT * FROM Customers WHERE City = @p0";
  14. context.Customers.FromSql(sql, city).ToArray();
  15. }

第一种方法,因为sql的赋值被编译成String.Format方法的调用,返回的是字符串。sql变量传入FromSql方法时,又经过一次System.StringMicrosoft.EntityFrameworkCore.RawSqlString隐式转换。但sql变量本身已经丢失了参数信息,所以无法实现参数化的查询。

第四种方法, 也是Interpolated Strings -> String -> RawSqlString的转换过程,但因为变量是分开传入FromSql方法的,所以是以参数化的方式执行的。

其他

熟悉ES2015的同学可以看看Javascript中的实现,Tagged template literals,这和Interpolated Strings 非常类似。

昨晚凌晨12点发帖,不知道为什么被移除首页了。感觉是篇幅不够的原因,重新加了点EF Core注意事项,但超过1小时没办法重新回首页了。七年来的第一篇文章,有点遗憾。希望大家喜欢。

C# 6.0 内插字符串 (Interpolated Strings )的更多相关文章

  1. C#6.0的新特性之内插字符串

    https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/interpolated-strings C# 6 ...

  2. C# 内插字符串与字符串复合格式

    var name = "Tom"; ; string aa = string.Format("name:{0},age:{1}", name, age);//字 ...

  3. Go中的字符串使用----strings和strconv

    Go中的字符串操作 字符串是工作中最常用的,值得我们专门的练习一下.在Go中使用strings包来操作字符串,这也是内置的包哈,不像Java中要么手写,要么引入common-lang 或者 别的第三方 ...

  4. C#控制内插字符串的格式

    C#6.0推出了内插字符串 结果展示: 内插表达式字段宽度和对齐方式: 结果展示:(+/-代表右对齐.左对齐,数字表示显示宽度)

  5. 为什么要用内插字符串代替string.format

    知道为什么要用内插字符串,只有踩过坑的人才能明白,如果你曾今使用string.format超5个以上占位符,那其中的痛苦我想你肯定是能够共鸣的. 一:痛苦经历 先上一段曾今写过的一段代码,大家来体会一 ...

  6. C# -- 内插字符串的使用

    C# -- 内插字符串的使用 (1) 字符串文本以 $ 字符开头,后接左双引号字符. $ 符号和引号字符之间不能有空格.(2) 内插字符串表达式的结果可以是任何数据类型.(3) 可通过在内插表达式后接 ...

  7. php: 0跟字符串做比较永远是true。 php大bug。

    php: 0跟字符串做比较永远是true. php大bug. 如: $a = 0; if( $a == 'excel') { echo "yes"; }else{ echo &qu ...

  8. guava字符串工具 Strings 校验补全 转换null和""

    public class StringsTest { public static void main(String args[]){ //1.补右全(Strings.padEnd方法) String ...

  9. [Swift]LeetCode859. 亲密字符串 | Buddy Strings

    Given two strings A and B of lowercase letters, return true if and only if we can swap two letters i ...

随机推荐

  1. c# 读写文件时文件正由另一进程使用,因此该进程无法访问该文件

    c# 读写文件时文件正由另一进程使用,因此该进程无法访问该文件,在IO处理上遇到了无法操作的问题. 文件"D:\log.txt"正由另一进程使用,因此该进程无法访问该文件. log ...

  2. 利用java反射机制编写solr通用的java客户端

    一.前言 通过上一篇的讲解,我们知道了dynamicFiled字段,它是动态的,不需要显示的声明.而且一些常用的基本类型solr已经默认给我们创建好了. 例如:*_i,*_is,等. 如果我们要使用动 ...

  3. JS之正则表达式

    一.正则表达的目标: 1.使用表单事件和脚本函数实现表单验证 2.使用String对象和文本框控件常用属性和方法实现客户端验证 二.什么需要表单验证: 1.表单元素是否为空 2.用户名和密码 3.E- ...

  4. encodeURI与decodeURI

    Global对象的ecodeURI方法可以对URI进行编码,与其类似的还有一个方法encodeURIComponent方法. 相应的对URI的解码方法也有两个:decodeURI.decodeURIC ...

  5. Java IO学习笔记(四)打印流

    1.只有输出流才有打印流:PrintWriter和PrintStream分别针对字符和字节,提供了重载的print,Println方法用于多种数据类型的输出.PrintWriter和PrintStre ...

  6. JS运动框架的封装过程(一)

    给大家出一道题,从起点A走到目的地B,一共用了1000毫秒,每一次是30毫秒,请问你在这里面得到了哪些信息? 信息有哪些呢? 第一个,总时长是:1000毫秒 第二个,多久时间走一次?30毫秒 第三个, ...

  7. 安装WIA组件

    下载地址: http://pan.baidu.com/s/1bnGU5Nx 安装方法: 将下载后的WIAAutSDK.zip解压,复制wiaaut.dll到C:\Windows\System32,注册 ...

  8. windows平台python 2.7环境编译安装zbar

    最近一个项目需要识别二维码,找来找去找到了zbar和zxing,中间越过无数坑,总算基本上弄明白,分享出来给大家. 一.zbar官方介绍 ZBar 是款桌面电脑用条形码/二维码扫描工具,支持摄像头及图 ...

  9. Chrome浏览器扩展开发系列之一:初识Google Chrome扩展

    1.       Google Chrome扩展简介 Google Chrome扩展是一种软件,以增强Chrome浏览器的功能. Google Chrome扩展使用HTML.JavaScript.CS ...

  10. linux可用更新源

    Kali 2.0更新源kali-rolling:#中科大deb http://mirrors.ustc.edu.cn/kali kali-rolling main non-free contribde ...