Как сделать статическую акцию в C #?

Для пары таких типов:

interface I {} class C : I {} 

Как я могу сделать статический тип? Под этим я имею в виду: как я могу изменить свой тип таким образом, который проверяется во время компиляции?

В C ++ вы можете сделать static_cast(c) . В C # лучше всего я могу создать временную переменную альтернативного типа и попытаться назначить ее:

 var c = new C(); I i = c; // statically checked 

Но это предотвращает свободное программирование. Я должен создать новую переменную только для проверки типа. Поэтому я решил что-то вроде этого:

 class C : I { public II { get { return this; } } } 

Теперь я могу статически преобразовать C в I, просто позвонив cI .

Есть ли лучший способ сделать это на C #?

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

ОБНОВИТЬ

Другой вариант, с которым я столкнулся, – это расширение объекта:

 public static class ObjectExtensions { [DebuggerStepThrough] public static T StaticTo(this T o) { return o; } } 

Итак, ((I)c).Doit() также может быть c.StaticTo().Doit() . Хм … возможно, все равно будет придерживаться простого актера. Понял, что я бы опубликовал этот другой вариант.

Напишите метод расширения, который использует трюк, упомянутый в вашем UPDATE:

 public static class ObjectExtensions { public static T StaticCast(this T o) => o; } 

Использовать:

 things.StaticCast().GetEnumerator(); 

Если это так, например, IEnumerable , это компилируется. Если things object , это терпит неудачу.

 // Compiles (because IEnumerable is known at compiletime // to be IEnumerable too). "adsf".StaticCast().GetEnumerator(); // error CS1929: 'object' does not contain a definition for 'StaticCast' // and the best extension method overload // 'ObjectExtensions.StaticCast(IEnumerable)' // requires a receiver of type 'IEnumerable' new object().StaticCast().GetEnumerator(); 

Зачем использовать Static Cast?

Одной из распространенных практик во время рефакторинга является продвижение и внесение изменений, а затем проверка того, что ваши изменения не вызвали никаких регрессий. Вы можете определять регрессии различными способами и на разных этапах. Например, некоторые типы рефакторинга могут приводить к изменению / потере API и требуют реорганизации других частей кодовой базы.

Если одна часть вашего кода ожидает получения типа ( ClassA ), который должен быть известен в compiletime для реализации интерфейса ( IInterfaceA ), и этот код хочет напрямую обращаться к членам интерфейса, ему может потребоваться передать тип интерфейса, например, , доступ к явно реализованным элементам интерфейса. Если после рефакторинга ClassA больше не реализует IIterfaceA , вы получаете разные типы ошибок в зависимости от того, как вы перешли на интерфейс:

  1. C-style cast: ((IInterfaceA)MethodReturningClassA()).Act(); внезапно превратится в бросок времени выполнения и выбросит ошибку времени выполнения.
  2. Присвоение явно типизированной переменной: IInterfaceA a = MethodReturningClassA(); a.Act(); IInterfaceA a = MethodReturningClassA(); a.Act(); приведет к сбою компиляции.
  3. Использование метода MethodReturningClassA().StaticCast().Act(); static_cast -like extension: MethodReturningClassA().StaticCast().Act(); приведет к сбою компиляции.

Если вы ожидали, что ваш бросок будет подавлен и будет поддаваться проверке в compiletime, вам следует использовать метод кастинга, который принудительно выполняет проверку. Это делает намерения первоначального разработчика кода писать код четного кода. И писать типичный код имеет преимущество быть более поддающимся проверке в compiletime. Сделав небольшую работу, чтобы прояснить ваше намерение выбрать типы безопасности как для других разработчиков, так и для вашего компилятора, вы волшебным образом получаете помощь компилятора в проверке кода и можете чаще ловить рефакторинг рефакторинга (в compiletime), чем позже ( например, сбой во время выполнения, если у вашего кода не было полного охвата тестирования).

Просто бросьте его:

 (I)c 

Изменить пример:

 var c = new C(); ((I)c).MethodOnI(); 
 var c = new C(); I i = c; // statically checked 

равно

 I i = new C(); 

Если вы действительно ищете способ увидеть, реализует ли объект определенный тип, вы должны использовать его as .

 I i = whatever as i; if (i == null) // It wasn't 

В противном случае вы просто бросаете его. (В .NET не так много типов кастингов, как в C ++ – если вы не углубляетесь больше, чем нужно большинству людей, но тогда речь идет о WeakReference и т. Д.).

 I i = (I)c; 

Если вы просто ищете удобный способ превратить что-либо, реализующее I в I , то вы можете использовать метод расширения или что-то подобное.

 public static I ToI(this I @this) { return @this; }