You can't implement this effectively.
You're running into what's generally referred to as the "DRM problem" - code running on a general purpose computing platform can always be subverted or modified by the owner of that system. Your code is no longer your code when it runs on a user system.
Designing these kinds of anti-dumping, anti-injection, anti-modification, anti-debugging, anti-cracking, anti-reversing, anti-emulation, anti-whatever-else-you-feel-like systems is an ongoing field of research and commercial effort. So far nobody has been able to produce an uncrackable protection. There have been cases where breaking protection was particularly difficult, but all schemes have eventually been broken somehow, even in the case where specialist hardware was used (see: HDCP, PS3 LV0 keys)
Discussion of what can be done to make things difficult for someone attempting to subvert your program could easily span a whole book, but here's a rough outline of tricks on a Windows platform:
- Anti-analysis tricks such as:
- Compression or encryption of code (packing)
- Virtual machines (implement a custom processor emulator, write code for that)
- Control-flow obfuscation
- String and data obfuscation
- Fake code
- Runtime code modification
- Anti-debug tricks such as:
- Early execution of code (pre-EntryPoint) using TLS callbacks.
- Execution time comparisons using
- Direct debugger checks (PEB flags,
- Exploiting vulnerabilities in common debuggers (e.g. OllyDbg
- Detection of common debuggers and tools via process names, window names, window classes, mutexes and other objects, drivers, presence of files
- Injecting debugger checks into other processes (e.g. explorer) to avoid them being identified.
- Endless others...
- Anti-modification tricks such as:
- Runtime checksums of critical code and data
- Shadow copies of critical data for later verification
- Encryption of memory using
- Moving critical operations to the kernel (using a driver) to make it harder for a user to tamper with code.
- VM detection (again whole books can be written on this)
- Hooking common APIs in all processes (either in usermode using DLL injection, or in the kernel) to deny or otherwise tamper with calls which attempt to access your process.
- Anti-tracing tricks using software breakpoints and exception handlers.
- General security hardening such as enabling NX + ASLR + ForceIntegrity, plus mitigation policies which may make it harder for software to access the process or inject DLLs.
Even if you implemented every feature on this list, it can all be bypassed with some work.
It's important to note that .NET itself doesn't necessarily have any real weakness to being memory edited that native (e.g. C, C++) executables don't. What makes .NET easier to attack in general is that the intermediate language (IL) instructions and metadata contained within can be more easily reverse engineered into something human-understandable, whereas native executables have more options for obfuscation and anti-reversing tricks and don't contain such metadata. The article you linked simply shows a way to use reflection to get access to the variable rather than a more native approach which would work just as well.