Как Правильно реализовать условную компиляцию с#?
Конечно можно вставлять в код самого приложения обычные условные операторы, проверяющие версию,.. но почему обязательно хотите избежать #директив препроцессора, фактически он для таких вещей и создавался!

Не хотите пользоваться штатным препроцессором - пилите свой, который будет под нужную версию подготавливать проект для сборки, буквально собирая его из файлов. Т.е. это будет приложение (простенькие скрипты и какое-то описание файлов проекта) которое вы будете запускать для создания релиза.
Нужно к примеру, ввести отчет о состояние объектов и ввести логирования, для одной версии программы, к примеру с помощью инъекции а для другой полностью убрать функционал для большей производительности. 
Всё это можно делать при помощи конфигурационных файлов