If you want a guaranteed safety from injection attacks, use bound parameters.
Your method may in practice actually be safe for a particular RDBMS, but you have no guarantee of this -- all you can do is check against the types of code-injection attacks that you can think to check against (while bound parameters simply
do not allow code to be injected).
Are you sure, MSSQL does not map any characters from alternate character sets (e.g., unicode) to internally to a single quote (or an escape character like \ ), that would make an injection attack against your defense possible? Are you sure later processing of your sanitized input does not inadvertently (or purposely by a malicious co-admin) break your sanitation procedure? Are you sure an update to MSSQL will not later include new language/character-set support that would allow someone to do this unicode style attack to secretly inject a quote or escape character? Are you sure, your application will never be moved to another RDBMS that is vulnerable to these sorts of attacks (say years from now if MSSQL is abandoned or clearly inferior to another product)?