Recently it was discussed why downcast is needed - type conversion from the more general to the more specific. Is upcast needed (boost casting) - explicit type casting in the opposite direction, from the more specific to the more general? After all, we do not lose anything, working with a more specific object?

    1 answer 1

    1. For starters, a common reason that concerns not only C #, but also most object-oriented languages: semantics. If a programmer has an object of a particular type, he may nevertheless want to work with him as with a more general object: programming against an interface, not implementation!

      This allows you to make sure that the code does not use unnecessary, specific properties, which will make it difficult in the future to generalize the code.

      Of course, this is usually too strict a goal, and you can do without it.

    2. The next reason is the choice of overload, non-polymorphic method. Depending on the static type of the object (with the same dynamic type), different overloads can be caused with the same looking code. Examples:

      Calling the desired overload:

      void f(object o) { Console.WriteLine("обрабатываем объект"); } void f(string s) { f((object)s); // избегаем рекурсии Console.WriteLine("дополнительная обработка для строки"); } string s = "Пушкин"; f(s); // вызывает перегрузку со строкой f((object)s); // вызывает перегрузку с объектом 

      Another example that is often found in the code:

       class X { public static bool operator == (X x1, X x2) { // оптимизация: проверим совпадение объектов if ((object)x1 == (object)x2) return true; // далее более дорогая проверка равенства по свойствам } } 

      Call a private method:

       class Base { public void X() { Console.WriteLine("нужный метод"); } } class Derived : Base { public new void X() { Console.WriteLine("бесполезный метод"); } } Derived d = new Derived(); ((Base)d).X(); 
    3. Explicit interface implementation does not allow calling a method by name.

       class X : IDisposable { void IDisposable.Dispose() {} } var x = new X(); // ... ((IDisposable)x).Dispose(); // по-другому не вызвать 
    4. In cases when the type of a variable is implicitly derived from the type of another variable, there are cases when we are not satisfied with the automatically inferred type. Example:

       var list = new[] { 1, 2 }.ToList(); list.Add("ой"); 

      We want to get a list of object 's, but type inference gives us a list of int 's. We can write

       var list = new[] { (object)1, 2 }.ToList(); list.Add("ой"); 

      so everything will be compiled.

      Another closely related case is the ternary operator. If the types of alternatives are different, the compiler cannot find the general type of the expression, and you have to help:

       Animal animal = nya ? new Cat() : new Dog(); // не компилируется Animal animal = nya ? (Animal)new Cat() : new Dog(); // компилируется 

      (A very similar problem occurs with Nullable types: int? result = good ? 1 : null requires explicit conversion of one of the alternative operands.)

      This case was suggested by @Pavel Mayorov in the comments, thanks!

    5. Another use is implicit boxing. For example, functions of type GetEnumerator() can return an object of value type that implements the IEnumerator<T> interface. Working with him is not always convenient:

       static public IEnumerable<R> MultiZip<T, R>( this IEnumerable<List<T>> sequences, Func<IEnumerable<T>, R> resultSelector) { var enumerators = sequences.Select(s => (IEnumerator<T>)s.GetEnumerator()).ToList(); try { while (enumerators.All(en => en.MoveNext())) yield return resultSelector(enumerators.Select(en => en.Current)); } finally { foreach (var en in enumerators) en.Dispose(); } } 

      If we had forgotten upcast to IEnumerator<T> , then the enumerators could be a set of value type (and this is the case in our case!). In this case, since we mutate our enumerators (MoveNext), for the case of the value type, we would call this method on a copy of the value, and thus the code would not work.

    • Waiting for reinterpret_cast ;-) - cpp_user pm
    • @VladD can be dispensed with by implicit apkast 2.1 - Object.ReferenceEquals(x1, x2) - PashaPash
    • @PashaPash: Yes, just an example of a valid application. If there is no such method (as, for example, in the example one above), then you cannot do without apkast in one form or another (for example, through an additional variable). [You meant 2.2, probably.] // Although, as you have already noted, object.ReferenceEquals also does (implicit) apkast. - VladD pm
    • @VladD: It is true that no, but as we would like. - cpp_user
    • @VladD: What is UB there? There the usual exception generation is: Type mismatch. - cpp_user 5:14