Переменная типа MembershipUser может содержать объект типа CustomMembershipUser, поскольку подтип является экземпляром супертипа.Но обратное неверно.
В CustomMembershipUser могут быть члены, которых нет в MembershipUser.Поэтому переменная типа CustomMembershipUser не может содержать объект типа MembershipUser.В противном случае код может попытаться получить доступ к одному из тех членов, которых он не содержит.
Сбой:
CustomMembershipUser custUser = memUser;
, поскольку вы можете выполнить его следующим образом:
custUser.CustomStuff(); // Oops! Can't call CustomStuff() on a MembershipUser object!
Сообщение «явное приведение существует»
Причина, по которой вы получаете сообщение «явное приведение существует», не в том, что вы создали приведение от пользователя к MembershipUser.(Тип User здесь вообще не задействован.) Это потому, что явное приведение всегда существует от супертипа до подтипа.Это часть языкового дизайна.Это необходимо для поддержки сценария, в котором вы знаете , что объект относится к подтипу, и вы хотите использовать соответствующую переменную.Но если вы используете это явное приведение к объекту, который не относится к целевому типу, вы получите ошибку времени выполнения (как вы уже видели).
Дальнейшее объяснение того, почему приведение не удается
В C # каждый объект имеет тип.Этот тип никогда не может быть изменен за время существования объекта.После того как вы создадите Employee (например), он всегда будет Employee навсегда или до момента сбора мусора, аминь.
public class Person
{
public string Name {get; private set;}
public Person(string name)
{ Name = name; }
}
public class Employee : Person
{
public DateTime HireDate {get; private set;}
public Employee(string name, DateTime hireDate)
: base (name)
{ HireDate = hireDate; }
}
Если у вас есть переменная типа Person, то эта переменная может содержатьобъект Employee, потому что Employee - это Person.
Employee mike = new Employee("Michael", DateTime.Now);
Person myBestBud = mike;
Это неявное приведение, потому что оно всегда работает.Переменная Person может всегда содержать объект Employee.Причина этого в том, что система знает, что каждый член Person, который она пытается использовать, будет доступен из-за наследования.
Console.WriteLine("Dude's name: " + myBestBud.Name);
Теперь давайте попробуем это по-другому.
Person johnny = new Person("Johnny Johnson");
Employee newHire = johnny; // ERROR - Attempt to assign...etc. An explicit cast is available...
Это вызывает ошибку.Не существует неявного приведения от Person к Employee, потому что компилятор не может гарантировать, что переменная Person содержит объект Employee.Так что это вызывает ошибку во время компиляции.Итак, давайте попробуем явное приведение.
Employee newHire = (Employee)johnny;
Это скомпилируется просто отлично.Это разрешено компилятором, потому что иногда переменная Person будет содержать объект Employee.Но это не удастся во время выполнения.Причина, по которой это не удастся, заключается в том, что переменная johnny не имеет сотрудника, поэтому ее нельзя рассматривать как единицу.Таким образом, выдается недопустимое исключение приведения.
Если оно не выдало недопустимое исключение приведения, то мы можем попытаться сделать что-то вроде этого:
Console.WriteLine("Hired on: " + newHire.HireDate);
Но свойство несуществует, потому что объект на самом деле является человеком, а не сотрудником.
Таким образом, вы можете видеть, что происходит преобразование имплика из подтипа в супертип, потому что это всегда успешно и не вызывает проблем.Существует явное приведение от супертипа к подтипу, потому что это работает, только если тип времени выполнения объекта совместим по присваиванию с переменной.Предполагается, что программист знает, когда он работает, а когда нет, и выполняет приведение только тогда, когда он будет работать.В противном случае среда выполнения обнаружит недопустимое приведение и выдаст исключение.
Теперь иногда пользователь может создать пользовательский оператор преобразования, который можно использовать для преобразования из одного типа в другой.Когда это происходит, то создается совершенно новый объект целевого типа.Однако это не может быть сделано вверх или вниз по иерархии наследования, потому что приведение типов к ним уже осуществляется компилятором C #.Для выполнения пользовательского оператора преобразования исходный или целевой тип не должен быть предком или потомком другого типа.