Страницы

Поиск по вопросам

вторник, 13 ноября 2018 г.

Как верно передать “класс” в метод?

Подскажите, пожалуйста, у меня есть два класса; (Star,Circle) Есть ли возможность передать данный класс в метод с вызовом его конструктора.
Сейчас использую дженереки, но конструктор не работает
Пример:
public static T getObj( int size, int i) where T : new() { return _objs[i] = new T(new Point(rnd.Next(0, 800), i * 20), new Point(5 - i, 15 - i), new Size(size, size)); }
Сам вызов:
getObj(3, i)
Ошибка: CS0417 'T": при создании экземпляра типа переменной не удается задать аргументы
как верно передать класс в метод заместо "new T"?


Ответ

То, в каком виде пытаетесь это сделать Вы, сделать не получится. Вы не можете наложить ограничение на T, чтобы у него обязательно был конструктор с указанными Вами типами параметров.
where T : new()
Данное ограничение new работает следующим образом:
Оно указывает, что аргумент любого переданного типа должен иметь открытый конструктор без параметров.
Как видите, нам это не подходит. Точнее, не совсем.Давайте рассмотрим несколько вариантов решения Вашей проблемы

#0. Наследование
Раз Вы пытаетесь объединить объекты, значит, они явно наделены общей логикой. А общую логику в ООП принято выносить в абстракции. Давайте так и поступим!
Я не знаю деталей реализации Вашей программы, но, судя по названиям, Вы работаете с некими фигурами. Запишем все это дело так:
// Абстрактный родительский класс public abstract class Shape { // Свойства, которые будут у всех его потомков public Point A { get; set; } public Point B { get; set; } public Size C { get; set; }
// Публичные инициализаторы public Shape() { } // Тот инициализатор, что Вы пытаетесь использовать public Shape(Point A, Point B, Size C) { this.A = A; this.B = B; this.C = C; } }
public class Circle : Shape { // Реализовываем нужные инициализаторы public Circle() { } public Circle(Point A, Point B, Size C) : base(A, B, C) { // SOMETHING } }
public class Star : Shape { // Реализовываем нужные инициализаторы public Star() { } public Star(Point A, Point B, Size C) : base(A, B, C) { // SOMETHING } }
Теперь же давайте изменим Ваш метод:
// Добавим ограничение, что T может являться только потомком Shape public static T GetShape(Point A, Point B, Size C) where T : Shape, new() { // Используем инициализатор по умолчанию, установив все свойства вручную T obj = new T { A = A, B = B, C = C };
return obj; }
Если же Вам нужно не просто установить значения свойств и в инициализатор спрятана какая-то хитрая логика, то метод можно переписать так:
// Добавим ограничение, что T может являться только потомком Shape public static T GetShape(Point A, Point B, Size C) where T : Shape { // Получим тип T Type type = typeof(T);
// Вручную сопоставим типы if (type == typeof(Star)) // Преобразуем Star к базовому классу, а после - к T, // который, как указано в ограничении, является Shape return (T)(Shape)new Star(A, B, C); else if (type == typeof(Circle)) // Преобразуем Circle к базовому классу, а после - к T, // который, как указано в ограничении, является Shape return (T)(Shape)new Circle(A, B, C);
// Если тип не опознан - выбросим ошибку throw new NotSupportedException(); }
Или же можно использовать сопоставление шаблонов из C# 7.0+ (данный вариант представлен больше для демонстрации указанных возможностей языка, чем для использования в реальных проектах):
// Добавим ограничение, что T может являться только потомком Shape public static T GetShape(Point A, Point B, Size C) where T : Shape, new() { // Инициализатор по умолчанию // Этот метод подразумевает создание объекта дважды, // что не очень логически верно. Не делайте так) T obj = new T();
// Используем паттерны сопоставления switch (obj) { case Star star: star = new Star(A, B, C); obj = (T)(Shape)star; break; case Circle circle: circle = new Circle(A, B, C); obj = (T)(Shape)circle; break; default: // Тип не распознан throw new NotSupportedException(); }
return obj; }


#1. Явное обращение к рефлексии
То, что Вы хотите, можно реализовать и с помощью нашей дорогой и любимой рефлексии (однако сразу предупреждаю, что это медленнее вышеописанного подхода. Не очень заметно на малых выборках, но все же именно поэтому рекомендуется использовать варианты выше) От слов к делу:
public static T GetShape(Point A, Point B, Size C) { // Получим тип T Type type = typeof(T);
// Получаем открытый конструктор, в который надо передать два объекта типа Point и один типа Size ConstructorInfo constructor = type.GetConstructor(new Type[] { typeof(Point), typeof(Point), typeof(Size) }); if (constructor != null) { try { // Вызовем конструктор с указанными параметрами object result = constructor.Invoke(new object[] { A, B, C });
// Если все прошло удачно, то приведем результат к указанному типу и вернем if (result != null) return (T)result; } catch (Exception ex) { // Ошибочка вышла, обработайте ее! throw new NotSupportedException(); } }
// У нас ничего не вышло, значит, тип не соответсвует заданным условиям throw new NotSupportedException(); }
Метод можно порядком ужать. Я все расписываю, чтобы Вам было удобнее и понятнее читать)
Как ужать? Таким образом, используя Activator.CreateInstance
public static T GetShape(Point A, Point B, Size C) { try { return (T)Activator.CreateInstance(typeof(T), A, B, C); } catch (Exception ex) { // Обработайте ошибку. Ее появление означает, // что у заданного типа нет нужного конструктора throw new NotSupportedException(); } }
Данный метод делает ровно то, что и предыдущий (описанный для Вашего лучшего понимания подноготной), только встроенными возможностями
С помощью рефлексии можно реализовать метод безо всякого наследования и сопоставления типов, так что метод динамически расширяем (то есть если Вы добавите еще 10 классов, реализующих указанный конструктор, Вам не придется менять данный метод для их создания, в отличие от описанных выше с помощью наследования)

UPD:
Спасибо @PashaPash за поправку!
Итак, согласно документации
T obj = new T();
также использует рефлексию для создания объекта.То есть данное выражение эквивалентно следующему:
T obj = Activator.CreateInstance();

Надеюсь, мой ответ помог Вам разобраться в вопросе и решил Вашу проблему! Удачи в Ваших начинаниях!

Правильная разметка таблицы в которой отсутствуют ячейки


Получается сделать так, но две лишних ячейки в thead. Как сделать правильно?
table, td, th { border: 1px solid black; border-collapse: collapse; } td { width: 50px; height: 50px; }

Test table


Ответ

Заведите для используемых ячеек свой класс:
table, td, th { border-collapse: collapse; } td { width: 50px; height: 50px; } .td { border: 1px solid black; }

Test table

Как узнать, что андроид приложение запустили на эмуляторе?

Разрабатываю андроид-приложение и очень важно чтобы оно не запускалось с помощью эмуляторов. Есть возможность проверить устройство на подлинность ?


Ответ

На en SO предлагают FINGERPRINT проверять:
public static boolean isEmulator() { return Build.FINGERPRINT.startsWith("generic") || Build.FINGERPRINT.startsWith("unknown") || Build.MODEL.contains("google_sdk") || Build.MODEL.contains("Emulator") || Build.MODEL.contains("Android SDK built for x86") || Build.MANUFACTURER.contains("Genymotion") || (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic")) || "google_sdk".equals(Build.PRODUCT); }
Можно попробовать воспользоваться Android emulator detector'ом.
Есть ещё такой вариант.

Как получить данные из камеры?

Вообще хотел бы получить данные из камеры, преобразовать это в flv формат, и вывести по rtmp, но наверное это только мечта. Пробывал ffmpeg программу прочитать, я почему то уверен что там всё грамотно написано, но я ничего не понел. Вот хотел бы узнать как в линуксе можно открыть устройство камеру и получить видео поток, чтобы вывести его на экран.


Ответ

Вот хотел бы узнать как в линуксе можно открыть устройство камеру и получить видео поток, чтобы вывести его на экран.
vlc /dev/video0
получить видео поток
Документация по v4l2
По замечанию @andreymal - краткий мануал
Открытие устройства
int fd;
fd = open("/dev/video0", O_RDWR); if (fd == -1) { // ... }
Подготовка к захвату кадров
struct v4l2_capability caps = {0}; if (-1 == ioctl(fd, VIDIOC_QUERYCAP, &caps)) { // ... }
Формат кадра
struct v4l2_format fmt = {0}; fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.fmt.pix.width = 320; fmt.fmt.pix.height = 240; fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG; fmt.fmt.pix.field = V4L2_FIELD_NONE;
if (-1 == ioctl(fd, VIDIOC_S_FMT, &fmt)) { // ... }
Подготовка буфферов
struct v4l2_requestbuffers req = {0}; req.count = 1; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_MMAP;
if (-1 == ioctl(fd, VIDIOC_REQBUFS, &req)) { // ... }
struct v4l2_buffer buf = {0}; buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = bufferindex; if(-1 == ioctl(fd, VIDIOC_QUERYBUF, &buf)) { // ... }
buffer = mmap (NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset);
Захват изображения
if(-1 == ioctl(fd, VIDIOC_STREAMON, &buf.type)) { // ... }
fd_set fds; FD_ZERO(&fds); FD_SET(fd, &fds); struct timeval tv = {0}; tv.tv_sec = 2; int r = select(fd+1, &fds, NULL, NULL, &tv); if(-1 == r) { // ... }
if(-1 == ioctl(fd, VIDIOC_DQBUF, &buf)) { // ... }

Множественное выделение строк в UITableView

Как реализовать multi-selection в UITableView?


Ответ

По умолчанию, UITableView поддерживает режим выбора только одной строки. Но можно создать свой multi-selection в UITbaleView. Чтобы таблица имела возможность множественного выбора нужно поставить стиль стандартного выделения "none" и самостоятельно отслеживать события и менять вид элементов. Для этого следует выполнить несколько шагов: Пусть на верхней панели таблицы есть кнопка "Edit", которая при переходе в edit-mode меняется на "Cancel". При переходе в режим редактирования снизу таблицы появляется панель инструментов с вариантами действий над элементами таблицы. Для обнаружения выделенных строк использовать метод tableView:didSelectRowAtIndexPath:. В этом методе мы будем добавлять только что выбранный элемент в коллекцию. Т.к. мы не можем полагаться на стандартный UITableView, мы должны создать коллекцию, содержащую выделенные в данный момент элементы. Также, при выборе элемента мы должны сменить фон элемента и отодвинуть его от левого края, чтобы поместить туда специальный индикатор выделения (наподобие checkbox). Панель инструментов нужно создать в методе viewDidLoad, добавив что-то подобное: actionToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 416, 320, 44)]; actionButton = [[[UIBarButtonItem alloc] initWithTitle:@"No Action" style:UIBarButtonItemStyleBordered target:self action:@selector(noAction:)] autorelease]; [actionToolbar setItems:[NSArray arrayWithObject:actionButton]]; Затем, в методе viewDidAppear мы можем добавить нашу панель инструментов в иерархию - (void)viewDidAppear:(BOOL)animated { [self.view.superview addSubview:actionToolbar]; } Стандартный режим редактирования для UITableView реализуется посредством вызова setEditing:animated:. Но т.к. Мы не собираемся использовать никакой из стандартных UITableViewCellEditingStyle, то вызов этого метода не является строго обязательным, но его можно будет использовать для уведомления UITableViewCell. Методы edit и cancel можно реализовать примерно так: - (void)edit:(id)sender { [self showActionToolbar:YES]; UIBarButtonItem *cancelButton = [[[UIBarButtonItem alloc] initWithTitle:@"Cancel" style:UIBarButtonItemStyleDone target:self action:@selector(cancel:)] autorelease]; [self.navigationItem setRightBarButtonItem:cancelButton animated:NO]; [self updateSelectionCount]; [self.tableView setEditing:YES animated:YES]; }
- (void)cancel:(id)sender { [self showActionToolbar:NO]; UIBarButtonItem *editButton = [[[UIBarButtonItem alloc] initWithTitle:@"Edit" style:UIBarButtonItemStylePlain target:self action:@selector(edit:)] autorelease]; [self.navigationItem setRightBarButtonItem:editButton animated:NO]; NSInteger row = 0; for (MultiSelectCellController *cellController in [tableGroups objectAtIndex:0]) { [cellController clearSelectionForTableView:self.tableView indexPath:[NSIndexPath indexPathForRow:row inSection:0]]; row++; } [self.tableView setEditing:NO animated:YES]; } Далее, при вызове setEditing у UITableView таблица вызывает setEditing у всех видимых элементов (UITableViewCell). Мы можем переопределить этот метод и использовать для перехода из режима в режим отдельно взятого элемента таблицы (показать или скрыть "галочку"). Проще всего это реализовать следующим образом: конкретно в методе setEditing мы инициируем relayout методом setNeedsLayout, а основной код поместим в layoutSubviews (теперь мы будем правильно перерисовывать элемент вне зависимости от того, что стало причиной перерисовки). - (void)setEditing:(BOOL)editing animated:(BOOL)animated { [self setNeedsLayout]; } Можно непосредственно в layoutSubviews и добавлять сам рисунок "галочки". Но с точки зрения организации кода это не очень красивое решение, т.к. подразумевается, что UITableViewCell - это только макет элемента. Поэтому лучше добавлять галочку уже в UITableView, но это неважно. Итак, в layoutSubviews мы будем отодвигать элемент от левого края, чтобы освободить место для "галочки", вот так: - (void)layoutSubviews { [UIView beginAnimations:nil context:nil]; [UIView setAnimationBeginsFromCurrentState:YES]; [super layoutSubviews]; if (((UITableView *)self.superview).isEditing) { CGRect contentFrame = self.contentView.frame; contentFrame.origin.x = 40; // делаем отступ self.contentView.frame = contentFrame; } else { CGRect contentFrame = self.contentView.frame; contentFrame.origin.x = 0; self.contentView.frame = contentFrame; } [UIView commitAnimations]; } Теперь осталось только поставить cell.selectionStyle = UITableViewCellSelectionStyleNone т.к. мы не хотим использовать стандартный selection. Вместо этого надо просто менять backgroundView у элемента. P.s. Пример можно посмотреть в приложении Mail.

Рисование кривых и многоугольников на Canvas

Работаю с 2d-графикой в Android с помощью класса Canvas. Существуют ли способы, позволяющие рисовать: Кривую второго порядка (quadratic curve) Кривую третьего порядка (cubic curve) Многоугольник (полигон) из массива точек [x, y]


Ответ

Для этого существует класс Path Многоугольник так: Path polygon = new Path(); polygon.moveTo(x1, y1); polygon.lineTo(x2, y2); polygon.lineTo(x3, y3); polygon.lineTo(x4, y4); polygon.lineTo(x5, y5); new Canvas().drawPath(polygon, new Paint()); Кривые второго и третьего порядка - так: Path curve = new Path(); curve.moveTo(x1, y1); curve.quadTo(x2, y2, x3, y3); //или //curve.cubicTo(x2, y2, x3, y3, x4, y4) new Canvas().drawPath(curve, new Paint());

Как скрывать блок div в зависимости от разрешения экрана?

Для разных разрешений экрана - своя структура сайта. В десктоп-версии все div'ы показывать (грубо говоря). В мобильной - кое-что хотелось бы убрать. Как это реализовать? У меня такие догадки: Получаем разрешение экрана и подгружаем нужный css. (В mobil.css - display:none.) Не подгружая другие css, люди как-то используют js для скрытия div. Что за способ такой и как это через js делается? Можно ли это сделать без js (слышал, что в старых мобилах js плохо работает). А без js и одним css файлом это можно реализовать или это невозможно? Буду рад любому совету! Спасибо!


Ответ

Как вариант, с использованием javascript ...

...
...