#c# #dynamic #duck-typing
#c# #динамический #утиный ввод
Вопрос:
У меня занятия с Пациентами:
class Patient {
public string First_Name { get; set; }
public string Last_Name { get; set; }
public DateTime Date_of_Birth { get; set; }
}
У меня также есть интерфейс:
interface IPerson {
string First_Name { get; }
string Last_Name { get; }
}
в этом консольном приложении я бы хотел, чтобы метод Display_Person работал. Он компилируется, но выдает ошибку во время выполнения, потому что Patient не реализует IPerson.
class Program {
static void Main(string[] args) {
Patient p = new Patient {
First_Name = "Charles", Last_Name = "Lambert",
Date_of_Birth = new DateTime(1976,5,12),
};
Display_Person(p);
}
static void Display_Person(dynamic person) {
IPerson p = person;
Console.WriteLine("{0}, {1}", p.Last_Name, p.First_Name);
}
}
Какие изменения в коде, не требуя от пациента реализации интерфейса IPerson, я могу внести, чтобы заставить метод Display_Person работать? Я бы предпочел решение, которое можно использовать повторно.
Обновление: я хочу, чтобы это сработало, чтобы я мог получить intellisense. Пожалуйста, не обращайте внимания на тривиальность этого примера. Это коротко и по существу объясняет мою проблему. Если бы это было 1003 заявки на получение кредита (при печати размером с книгу), я бы не хотел применять более 20 интерфейсов к своему классу, чтобы я мог группировать связанные данные для вычислений. Мне также не хотелось бы каждый раз вводить все эти свойства. Отсутствие intellisense в прошлом отвлекало меня от использования динамических языков. (Я не ленивый, я эффективный!)
Комментарии:
1. Если вы действительно хотите, чтобы intellisense работал, используйте его, как вы делали в своем примере, избавьтесь от строки IPerson и измените параметр ‘person’ на ‘p’. Не идеально, но intellisense знает столько, сколько позволяет ваш код.
Ответ №1:
Для этого вы можете использовать импровизированный интерфейс.
Комментарии:
1. как бы ни было круто ваше предложение. Это не работает с непубличными интерфейсами. Также, если динамический тип на самом деле является определенным типом, например, моим
Patient
классом. Он выдает ошибку времени выполнения, котораяPatient
не реализуетActLike()
метод.2. Это странно, я широко использовал его для приведения динамических объектов к интерфейсам. Вы пробовали альтернативный синтаксис:
Impromptu.ActLike<IMyInterface>(expando);
?3. Он отлично работает, если он общедоступный.
dynamicVariableName.ActLike<IInterface>()
вообще не сработало. `Экспромт. ActLike<IInterface>() работает только тогда, когда интерфейс является общедоступным. Я думаю, это не может отразиться на внутренних членах.4. Я попытался добавить an
InternalsVisibleToAttribute
в сборку, и это все равно не решило проблему. Я предполагаю, что импровизированная библиотека отражает только общедоступные элементы. Я собираюсь отправить туда свой пример кода и посмотреть, не ошибка ли это.5. @CharlesLambert Проблема не в том, чтобы размышлять о внутренних элементах, это работает нормально, сложность заключается в создании нового типа, который наследуется от внутреннего интерфейса.
[assembly: InternalsVisibleTo("ImpromptuInterfaceDynamicAssembly")]
тем не менее, следует решить проблему.
Ответ №2:
Если вы действительно хотите использовать dynamic, тогда зачем преобразование?
static void Display_Person(dynamic person) {
Console.WriteLine("{0}, {1}", person.Last_Name, person.First_Name);
}
Но я бы все же предпочел, чтобы Patient реализовал IPerson. Это имело бы гораздо больше смысла с точки зрения дизайна, а безопасность типов означает, что любая ошибка будет обнаружена во время компиляции, а не во время выполнения.
Ответ №3:
Нет! Я не думаю (без реализации IPatient), что это возможно. Вы должны реализовать IPatient
интерфейс
class Patient : IPatient {}
Или удалить приведение.
static void Display_Person(dynamic person)
{
Console.WriteLine("{0}, {1}", person.Last_Name, person.First_Name);
}
Ответ №4:
IPerson не нужен. Просто сделайте Display_Person
так:
static void Display_Person(dynamic person) {
Console.WriteLine("{0}, {1}", person.Last_Name, person.First_Name);
}
Пока person
эти свойства реализуются, это работает нормально.