English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

C# базовый курс

C# продвинутый курс

C#面向对象(OOP)

Полиморфизм в C#

Полиморфизм - это способность одного поведения иметь несколько различных форм или представлений.

ПолиморфизмЭто означает, что есть несколько форм. В парадигме объектно-ориентированного программирования полиморфизм часто проявляется как "один интерфейс, несколько функций".

Полиморфизм может быть статическим или динамическим. ВСтатическая полиморфностьВремя ответа функции наступает в време компиляции. Вдинамическая полиморфизмВремя ответа функции наступает в време выполнения.

В C# каждый тип является полиморфным, так как все типы, включая пользовательские типы, наследуются от Object.

Полиморфизм заключается в том, что один и тот же интерфейс может выполнять различные действия с использованием различных примеров, как показано на рисунке:

В реальной жизни, например, когда мы нажимаем клавишу F1:

  • Если вы находитесь в интерфейсе Flash, открывается документация AS 3;

  • Если вы находитесь в Word, открывается помощь для Word;

  • В Windows открывается Windows Help and Support.

Одно и то же событие, происходящее на разных объектах, может привести к различным результатам.

Статическая полиморфность

В време на компиляция, механизм связи между функциями и объектами называется ранним связыванием или статическим связыванием. C# предоставляет два метода для реализации статической полиморфности. Это:

  • Перегрузка функций

  • Перегрузка операторов

Перегрузка операторов будет рассмотрена в следующей главе,接下来我们将讨论函数重载。

Перегрузка функций

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

ниже приведен пример нескольких одинаковых функций Add(),用于对不同个数参数进行相加处理:

using System;
namespace PolymorphismApplication
{'}}
    public class TestData  
    {'}}  
        public int Add(int a, int b, int c)  
        {'}}  
            return a + b + c;  
        }  
        public int Add(int a, int b)  
        {'}}  
            return a + b;  
        }  
    }  
    class Program  
    {'}}  
        static void Main(string[] args)  
        {'}}  
            TestData dataClass = new TestData();
            int add1 = dataClass.Add(1, 2);  
            int add2 = dataClass.Add(1, 2, 3);
            Console.WriteLine("add1: " + add1);
            Console.WriteLine("add2: " + add2);  
        }  
    }  
}

ниже приведен пример нескольких одинаковых функций print()для вывода различных типов данных:

using System;
namespace PolymorphismApplication
{'}}
   class Printdata
   {'}}
      void print(int i)
      {'}}
         Console.WriteLine("вывод целого числа: {0}", i);
      }
      void print(double f)
      {'}}
         Console.WriteLine("вывод плавающей точки: {0}", f);
      }
      void print(string s)
      {'}}
         Console.WriteLine("вывод строки: {0}", s);
      }
      static void Main(string[] args)
      {'}}
         Printdata p = new Printdata();
         // вызов print для вывода целого числа
         p.print(1);
         // вызов print для вывода плавающей точки
         p.print(1.23);
         // вызов print для вывода строки
         p.print("Hello w3codebox");
         Console.ReadKey();
      }
   }
}

Когда этот код компилируется и выполняется, он produces следующие результаты:

вывод целого числа: 1
вывод плавающей точки: 1.23
вывод строки: Hello w3codebox

динамическая полиморфизм

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

Обратите внимание, что ниже приведены некоторые правила, касающиеся абстрактных классов:

  • нельзя создать пример абстрактного класса.

  • нельзя объявлять абстрактный метод вне абстрактного класса.

  • путем放置 ключевого слова перед определением класса sealedкласс может быть объявлен какзакрытый класс. Когда класс объявлен как sealed в этот момент он не может быть наследован. Абстрактный класс не может быть объявлен как sealed.

ниже приведен пример абстрактного класса:

using System;
namespace PolymorphismApplication
{'}}
   abstract class Shape
   {'}}
       abstract public int area();
   }
   class Rectangle: Shape
   {'}}
      private int length;
      private int width;
      public Rectangle(int a=0, int b=0)
      {'}}
         length = a;
         width = b;
      }
      public override int area()
      {'}} 
         Console.WriteLine("Площадь класса Rectangle:");
         return (width * length); 
      }
   }
   class RectangleTester
   {'}}
      static void Main(string[] args)
      {'}}
         Rectangle r = new Rectangle(10, 7);
         double a = r.area();
         Console.WriteLine("Площадь: {0}", a);
         Console.ReadKey();
      }
   }
}

Когда этот код компилируется и выполняется, он produces следующие результаты:

Площадь класса Rectangle:
Площадь: 70

Когда функция определена в классе и её нужно реализовать в классах наследования, можно использоватьВиртуальный метод.

Виртуальный метод используется с ключевым словом virtual является.

Виртуальный метод может иметь разное реализацию в различных классах наследования.

вызов виртуального метода происходит в время выполнения.

Динамическая полиморфность через Абстрактный класс и Виртуальный метод implement.

Ниже приведен пример создания базового класса Shape, а также производных классов Circle, Rectangle, Triangle. Класс Shape предоставляет виртуальный метод под названием Draw, который нужно перегрузить в каждом производном классе для рисования заданной формы.

using System;
using System.Collections.Generic;
public class Shape
{'}}
    public int X { get; private set; }
    public int Y { get; private set; }
    public int Height { get; set; }
    public int Width { get; set; }
   
    // Виртуальный метод
    public virtual void Draw()
    {'}}
        Console.WriteLine("Выполнить задачу рисования базового класса");
    }
}
class Circle : Shape
{'}}
    public override void Draw()
    {'}}
        Console.WriteLine("Нарисовать круг");
        base.Draw();
    }
}
class Rectangle : Shape
{'}}
    public override void Draw()
    {'}}
        Console.WriteLine("Нарисовать прямоугольник");
        base.Draw();
    }
}
class Triangle : Shape
{'}}
    public override void Draw()
    {'}}
        Console.WriteLine("Нарисовать треугольник");
        base.Draw();
    }
}
class Program
{'}}
    static void Main(string[] args)
    {'}}
        // Создание объекта List<Shape> и добавление в него Circle, Triangle и Rectangle
        var shapes = new List<Shape>
        {'}}
            new Rectangle()
            new Triangle(),
            new Circle(),
        };
        // Использование цикла foreach для циклического доступа к списку производных классов и вызова метода Draw для каждого объекта Shape 
        foreach (var shape in shapes)
        {'}}
            shape.Draw();
        }
        Console.WriteLine("Нажмите любую клавишу для выхода.");
        Console.ReadKey();
    }
}

Когда этот код компилируется и выполняется, он produces следующие результаты:

Нарисовать прямоугольник
Выполнение рисования базового класса
Нарисовать треугольник
Выполнение рисования базового класса
Нарисовать круг
Выполнение рисования базового класса
Нажмите любую клавишу для выхода.

Ниже приведен пример программы, демонстрирующей расчет площади различных фигур через виртуальный метод area():

using System;
namespace PolymorphismApplication
{'}}
   class Shape 
   {'}}
      protected int width, height;
      public Shape(int a = 0, int b = 0)
      {'}}
         width = a;
         height = b;
      }
      public virtual int area()
      {'}}
         Console.WriteLine("Площадь родительского класса:");
         return 0;
      }
   }
   class Rectangle: Shape
   {'}}
      public Rectangle(int a = 0, int b = 0): base(a, b)
      {'}}
      }
      public override int area()
      {'}}
         Console.WriteLine("Площадь класса Rectangle:");
         return (width * height); 
      }
   }
   class Triangle: Shape
   {'}}
      public Triangle(int a = 0, int b = 0): base(a, b)
      {'}}
      
      }
      public override int area()
      {'}}
         Console.WriteLine("Площадь класса Triangle:");
         return (width * height / 2); 
      }
   }
   class Caller
   {'}}
      public void CallArea(Shape sh)
      {'}}
         int a;
         a = sh.area();
         Console.WriteLine("Площадь: {0}", a);
      }
   }  
   class Tester
   {'}}
      
      static void Main(string[] args)
      {'}}
         Caller c = new Caller();
         Rectangle r = new Rectangle(10, 7);
         Triangle t = new Triangle(10, 5);
         c.CallArea(r);
         c.CallArea(t);
         Console.ReadKey();
      }
   }
}

Когда этот код компилируется и выполняется, он produces следующие результаты:

Площадь класса Rectangle:
Площадь: 70
Площадь класса Triangle:
Площадь: 25