This is not wholly impossible. There's a type of compiler called a transpiler that will take source code written in one language and compile it, not to bytecode or machine instructions, but to equivalent source code in another language.
Unity for instance uses this technique to transpile its hlsl-like Shaderlab code to glsl for platforms that don't use DirectX. (As well as a variant on the idea in IL2CPP to transform CIL bytecode to C++)
So, in theory, you could write a C# library with an API equivalent to an hlsl/glsl shader environment, write your shader in C#, and either run it on the CPU to emulate a GPU, or transpile it to equivalent hlsl/glsl to send to a real graphics card.
In the comments below, Theraot has provided a link to a project that does something like this.
But I don't think you gain anything by doing that.
C#, hlsl, and glsl syntax all descend from the same C-like conventions, so your code would look almost identical. You wouldn't really gain any particular ease of use this way.
Some idioms that are easy to express in shader languages, like annotating semantics, swizzling to swap the order of components of a vector, or constructing temporary vectors without new
, arecan be more cumbersome to express in C# — so your code could even end up a bit more complicated in this form.
Worse, there are a lot of things that would be valid C# that are not valid in a shader, like side effects that mutate global state in the middle of a fragment shader. Shader languages are deliberately constructed to ensure you can't break the rules like this. Your C# version would need good error reporting from your transpiler to catch these errors, because the C# compiler thinks they're OK.
So really, the biggest hurdle in writing shaders is wrapping your head around the massively parallel paradigm they use. Just swapping the language won't make that easier.
So, I'd argue you're much better off just picking up hlsl or glsl — there's very little new syntax to learn, and you won't need a complicated emulation environment. Or, if you want to work your way up slowly, consider using a nodegraph based shader editor to get a feel for the operations in a shader, without writing code at all. Once you understand the data flows, replacing nodes with familiar C-like code should be no big obstacle.