#c# #interface
#c# #интерфейс
Вопрос:
У меня возникла небольшая проблема с приведением моих объектов в C #, чтобы иметь возможность использовать дополнительные объектные методы, помимо тех, которые объявлены в интерфейсе. Ниже приведен простой пример того, о чем я говорю.
public interface IShape
{
void Print();
}
public class Square : IShape
{
#region IShape Members
public void Print()
{
HttpContext.Current.Response.Write("Square Print Called");
}
#endregion
public void PrintMore()
{
HttpContext.Current.Response.Write("Square Print More Called");
}
}
Почему при вызове этого кода ниже я не могу получить доступ к PrintMore()?
IShape s = (Square)shape;
s.PrintMore() // This is not available. only Print() is.
Любая помощь и объяснение были бы полезны?
Комментарии:
1. Потому что ваш объект является «формой», а не «квадратом». Это «проблема» приведения. Это абсолютно нормально 🙂
2. Ваш конечный регион находится не в том месте. Это немного сбивает с толку.
3. @CodeInChaos: Я не думаю, что это так. В интерфейсе есть только один метод, и он находится внутри региона. Неинтерфейсный метод находится за его пределами…
4. @Chris проверьте историю редактирования. Это было на момент комментария.
5. @CodeInChaos: Ах, мои извинения. Обычно я стараюсь быть хорошим в этом, но, очевидно, на этот раз пропустил это. 🙂
Ответ №1:
Ваша s
переменная по-прежнему имеет тип IShape
. То, что вы случайно использовали приведение при присвоении ему, не меняет тип с точки зрения компилятора. Вам понадобится:
Square s = (Square) shape;
s.PrintMore();
Конечно, это сработает, только если shape
действительно является a Square
(при условии, что не выполняются пользовательские преобразования).
Однако я бы посоветовал вам тщательно подумать, прежде чем идти по этому пути. Обычно подобное приведение указывает на то, что вы несколько нарушаете абстракцию — если вы знаете только о shape
качестве IShape
, вы должны (обычно) быть в состоянии делать то, что вам нужно, только с членами IShape
. Если это не так, вы можете:
- Сделать
IShape
более мощным (предоставить ему больше элементов) - Измените свой код, чтобы он принимал
Square
вместо anIShape
- Приведение при крайней необходимости
Комментарии:
1. Спасибо за замечания. Я пытаюсь дойти до того, что я полностью понимаю правильный подход и стоящие за ним рассуждения. Иногда решение отличное, но если вы никогда не поймете почему, это не поможет.
Ответ №2:
Проблема в том, что вы пытаетесь получить доступ PrintMore()
из IShape
ссылки, IShape
ссылки видят только Print()
метод, который они объявляют.
Итак, приведение, которое у вас есть, (Square) shape
ничего не делает, потому что оно немедленно сохраняет его в IShape
ссылку. Вам нужно, чтобы сама ссылка была Square
либо приведена в действие и сохранена в Square
ссылке, либо приведена в действие перед вызовом:
Square s = (Square) shape;
s.PrintMore();
Или
IShape s = shape;
((Square)s).PrintMore();
Или, если вы не уверены, является ли это Square
или нет, используйте as
приведение:
Square s = shape as Square;
// will cast if it is a Square, otherwise, returns null
// this doesn't work for value types (int, struct, etc)
if (s != null)
{
s.PrintMore();
}
Ответ №3:
В строке IShape s = (Square)shape;
вы сообщаете компилятору, что s является IShape, поэтому доступны только методы в IShape.
Если вы пользователь:
Square s = (Square)shape;
s.PrintMore()
Тогда это должно делать то, что вы хотите.
Ключевым моментом здесь является то, что когда вы объявляете переменную, вы сообщаете компилятору, что это такое, и тогда не имеет значения, какой объект вы в нее вставляете.
Ответ №4:
IShape s = (Square)shape;
s.PrintMore();
С этим кодом s
все еще является IShape
, а не Square
. Переменная сохраняет тип, который вы определили при ее объявлении, что бы вы ни пытались в нее ввести.
Для работы код должен быть :
Square s = (Square)shape;
s.PrintMore();
Комментарии:
1. На самом деле это не отвечает на его вопрос — почему?
2. @JoelEtherton : добавлены некоторые пояснения.
Ответ №5:
Причина, по которой вы не можете получить доступ к PrintMore
методу, заключается в том, что вы переназначаете приведенную к типу форму обратно переменной, определенной как IShape
. Чтобы иметь возможность использовать методы в Square
классе, вам нужно сохранить его в переменной типа Square
, например:
Square s = (Square)shape;
s.PrintMore();
или альтернативно:
((Square) shape).PrintMore();
Хотя, возможно, стоило бы хорошенько взглянуть на ваш код, приведения типов, подобные этим, обычно являются хорошим предупреждающим знаком о том, что, возможно, он не идеален. Возможно, IShape
следует использовать PrintMore
метод, или, возможно, вам следует принимать только Square
объекты на этом этапе? По крайней мере, я бы посоветовал убедиться, что shape
действительно имеет тип Square
, прежде чем выполнять приведение этого типа.
Например:
Square s = shape as Square;
if (s != null)
s.PrintMore();
Ответ №6:
Потому что, когда вы пытаетесь s.PrintMore()
, «s» имеет тип IShape, поэтому он знает только о функциях интерфейса. Вам нужно было бы сделать что-то вроде
Square s = (Square)shape;
s.PrintMore();
или
((Square)shape).PrintMore(); // assuming you're positive its a Square type
Представьте интерфейс как оболочку над вашим объектом, которая предоставляет только функции, определенные в интерфейсе. Они все еще существуют, вы просто не можете получить к ним доступ без приведения к соответствующему объекту.