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

var city = "London";

using (var context = CreateContext())
{
context.Customers
.FromSql($@"
SELECT *
FROM Customers
WHERE City = {city}")
.ToArray();
}

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

@p0='London' (Size = 4000)

SELECT *
FROM Customers
WHERE City = @p0

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

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

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

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

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

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

用代码来回答这个问题:

var name = "world";
string str1 = $"hello {name}"; //等于 var str1 = $"hello {name}";
IFormattable str2 = $"hello {name}";
FormattableString str3 = $"hello {name}";

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

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

FormattableString 是什么?

先看一段代码

var name = "world";
FormattableString fmtString = $"hello {name}";
Console.WriteLine(fmtString.ArgumentCount); //1
Console.WriteLine(fmtString.Format); //hello {0}
foreach (var arg in fmtString.GetArguments())
{
Console.WriteLine(arg); //world
Console.WriteLine(arg.GetType()); //System.String
}

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

EF Core 中的注意事项

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

var city = "London";

using (var context = CreateContext())
{
//方法一,非参数化
var sql = $" SELECT * FROM Customers WHERE City = {city}";
context.Customers.FromSql(sql).ToArray(); //方法二,参数化
context.Customers.FromSql($" SELECT * FROM Customers WHERE City = {city}").ToArray(); //方法三,参数化
FormattableString fsql = $" SELECT * FROM Customers WHERE City = {city}";
context.Customers.FromSql(fsql).ToArray(); //方法四,非参数化
var sql = " SELECT * FROM Customers WHERE City = @p0";
context.Customers.FromSql(sql, city).ToArray(); }

第一种方法,因为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. jmeter3.2版本完美实现Load Test报表

    今天下载了最新版的apache tomcat jmeter 3.2,需要jdk1.8以上的版本. 用非GUI模式运行压力测试后,出现的报表太完美了. 将jmx脚本放在就jmeter_home下的Scr ...

  2. Angular4 后台管理系统搭建(1) - 建立一个通用的Wijmo5 flexgrid分页器组件

    17年4月,开始学习angular2,到5月跟着升级到angular4.目前还在学习,搭建中.我的最终目的是用angular4框架搭建一个后台管理系统.这里使用了三个关键的外部库. 1.使用admin ...

  3. [leetcode-508-Most Frequent Subtree Sum]

    Given the root of a tree, you are asked to find the most frequent subtree sum. The subtree sum of a ...

  4. [leetcode-560-Subarray Sum Equals K]

    Given an array of integers and an integer k, you need to find the total number of continuous subarra ...

  5. 【Android Developers Training】 39. 获取文件信息

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  6. SharePoint 2016 安装配置流程及需要注意的地方

    1. 安装域, 安装后创建一个用户用于之后的安装配置, 例如 SPAdmin@XXXXX.com 2. 安装sql server 2016 将要安装sql server 的服务器加入域,   并将域账 ...

  7. 超好用的memcache管理及可视化监控工具,真方便!

    memcache做为主流的缓存数据库之一,广泛在各互联网平台使用,但是大家使用中都知道memcache目前没有一个比较好用的可视化客户端工具,每次都要输入命令进行操作,十分不方便.  而另一款主流缓存 ...

  8. java中方法的定义

    所谓的方法(将方法称为函数)指的就是一段可以被重复调用的代码块. 对于方法的返回值类型有两种使用形式: · 有数据返回:返回值类型就使用 Java 中定义的数据类型: · 无数据返回:使用 void ...

  9. 1.0 配置 appium + java的环境

    1. 配置 appim的环境前面中写到.       2. 在eclipse中配置 java 环境, 具体步骤:       <1>:在 eclipse 中新建 一个java 项目.   ...

  10. 用VS Code体验调试.NET Core 2.0 Preview (传统三层架构)

    准备工作 VS Code下载地址:https://vscode.cdn.azure.cn/stable/379d2efb5539b09112c793d3d9a413017d736f89/VSCodeS ...