C# 6.0 内插字符串 (Interpolated Strings )
看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.String
到Microsoft.EntityFrameworkCore.RawSqlString
隐式转换。但sql变量本身已经丢失了参数信息,所以无法实现参数化的查询。
第四种方法, 也是Interpolated Strings -> String -> RawSqlString的转换过程,但因为变量是分开传入FromSql方法的,所以是以参数化的方式执行的。
其他
熟悉ES2015的同学可以看看Javascript中的实现,Tagged template literals,这和Interpolated Strings 非常类似。
昨晚凌晨12点发帖,不知道为什么被移除首页了。感觉是篇幅不够的原因,重新加了点EF Core注意事项,但超过1小时没办法重新回首页了。七年来的第一篇文章,有点遗憾。希望大家喜欢。
C# 6.0 内插字符串 (Interpolated Strings )的更多相关文章
- C#6.0的新特性之内插字符串
https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/interpolated-strings C# 6 ...
- C# 内插字符串与字符串复合格式
var name = "Tom"; ; string aa = string.Format("name:{0},age:{1}", name, age);//字 ...
- Go中的字符串使用----strings和strconv
Go中的字符串操作 字符串是工作中最常用的,值得我们专门的练习一下.在Go中使用strings包来操作字符串,这也是内置的包哈,不像Java中要么手写,要么引入common-lang 或者 别的第三方 ...
- C#控制内插字符串的格式
C#6.0推出了内插字符串 结果展示: 内插表达式字段宽度和对齐方式: 结果展示:(+/-代表右对齐.左对齐,数字表示显示宽度)
- 为什么要用内插字符串代替string.format
知道为什么要用内插字符串,只有踩过坑的人才能明白,如果你曾今使用string.format超5个以上占位符,那其中的痛苦我想你肯定是能够共鸣的. 一:痛苦经历 先上一段曾今写过的一段代码,大家来体会一 ...
- C# -- 内插字符串的使用
C# -- 内插字符串的使用 (1) 字符串文本以 $ 字符开头,后接左双引号字符. $ 符号和引号字符之间不能有空格.(2) 内插字符串表达式的结果可以是任何数据类型.(3) 可通过在内插表达式后接 ...
- php: 0跟字符串做比较永远是true。 php大bug。
php: 0跟字符串做比较永远是true. php大bug. 如: $a = 0; if( $a == 'excel') { echo "yes"; }else{ echo &qu ...
- guava字符串工具 Strings 校验补全 转换null和""
public class StringsTest { public static void main(String args[]){ //1.补右全(Strings.padEnd方法) String ...
- [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 ...
随机推荐
- c# 读写文件时文件正由另一进程使用,因此该进程无法访问该文件
c# 读写文件时文件正由另一进程使用,因此该进程无法访问该文件,在IO处理上遇到了无法操作的问题. 文件"D:\log.txt"正由另一进程使用,因此该进程无法访问该文件. log ...
- 利用java反射机制编写solr通用的java客户端
一.前言 通过上一篇的讲解,我们知道了dynamicFiled字段,它是动态的,不需要显示的声明.而且一些常用的基本类型solr已经默认给我们创建好了. 例如:*_i,*_is,等. 如果我们要使用动 ...
- JS之正则表达式
一.正则表达的目标: 1.使用表单事件和脚本函数实现表单验证 2.使用String对象和文本框控件常用属性和方法实现客户端验证 二.什么需要表单验证: 1.表单元素是否为空 2.用户名和密码 3.E- ...
- encodeURI与decodeURI
Global对象的ecodeURI方法可以对URI进行编码,与其类似的还有一个方法encodeURIComponent方法. 相应的对URI的解码方法也有两个:decodeURI.decodeURIC ...
- Java IO学习笔记(四)打印流
1.只有输出流才有打印流:PrintWriter和PrintStream分别针对字符和字节,提供了重载的print,Println方法用于多种数据类型的输出.PrintWriter和PrintStre ...
- JS运动框架的封装过程(一)
给大家出一道题,从起点A走到目的地B,一共用了1000毫秒,每一次是30毫秒,请问你在这里面得到了哪些信息? 信息有哪些呢? 第一个,总时长是:1000毫秒 第二个,多久时间走一次?30毫秒 第三个, ...
- 安装WIA组件
下载地址: http://pan.baidu.com/s/1bnGU5Nx 安装方法: 将下载后的WIAAutSDK.zip解压,复制wiaaut.dll到C:\Windows\System32,注册 ...
- windows平台python 2.7环境编译安装zbar
最近一个项目需要识别二维码,找来找去找到了zbar和zxing,中间越过无数坑,总算基本上弄明白,分享出来给大家. 一.zbar官方介绍 ZBar 是款桌面电脑用条形码/二维码扫描工具,支持摄像头及图 ...
- Chrome浏览器扩展开发系列之一:初识Google Chrome扩展
1. Google Chrome扩展简介 Google Chrome扩展是一种软件,以增强Chrome浏览器的功能. Google Chrome扩展使用HTML.JavaScript.CS ...
- linux可用更新源
Kali 2.0更新源kali-rolling:#中科大deb http://mirrors.ustc.edu.cn/kali kali-rolling main non-free contribde ...