.NET Core 2.2中插值字符串未转为FormattableString问题咨询
你忽略了C#中插值字符串的类型解析优先级规则——默认情况下,$"" 格式的插值字符串会被隐式转换为 string,而不是 FormattableString,除非你明确指定类型,或者方法没有接受 string 的重载。
为什么第二个输出不符合预期?
你的代码里有两个 FromSql 重载:一个接受 string,一个接受 FormattableString。当你调用 FromSql($"SELECT * FROM tbl WHERE fld = {filter}") 时,编译器会优先选择接受 string 的重载(因为字符串转换是C#内置的基础转换,优先级高于 FormattableString 这种用户定义的转换)。
所以第二个调用实际上执行的是 string 版本的 FromSql,直接返回了插值后的原始字符串——也就是你看到的 SELECT * FROM tbl WHERE fld = Mark'; DROP TABLE tbl; --(这里没有单引号是因为插值字符串直接替换了变量值,不像第一个调用那样手动添加了单引号)。
如何让第二个调用和第三个输出一致?
你需要明确告诉编译器把插值字符串当作 FormattableString 处理,有两种方式:
1. 显式强制转换类型
把插值字符串转换为 FormattableString 后再传入:
Console.WriteLine(FromSql((FormattableString)$"SELECT * FROM tbl WHERE fld = {filter}"));
2. 调整方法重载(可选)
如果希望所有插值字符串调用都默认走参数化逻辑,可以移除 string 版本的 FromSql,或者让 string 版本内部调用 FormattableString 版本(不过这种方式要注意原始字符串的场景)。
补充:EF Core中的实际场景
在EF Core中,官方提供的 FromSql(旧版本)或 FromSqlInterpolated(新版本)方法就是通过接受 FormattableString 来自动实现参数化查询的,从而避免SQL注入。而 FromSqlRaw 则接受 string,需要手动传入参数,这和你写的两个重载的逻辑是一致的。
内容的提问来源于stack exchange,提问作者Teejay

