Страницы

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

пятница, 19 октября 2018 г.

Передача аргументов в функцию через |

Частенько вижу, что аргументы в функцию передаются так:
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_JOYSTICK)
К указанным параметрам можно добавить и другие, также разделив их вертикальной чертой |. Объясните, пожалуйста, как это работает.


Ответ

операция | - стандартная во многих языках операция побитового ИЛИ. Т.е. она применима к 2 числам и для каждого бита будет выполнено побитовое или. Пример:
310 | 1010 = 00112 | 10102 = 10112 = 1110
Это особенно удобно при использовании флагов как констант - степеней 2.
Например у нас есть FLAG_A = 110, FLAG_B = 210, FLAG_C = 410 и так далее. Тогда FLAG_A | FLAG_C = 510 и в обратную сторону, 510 можно получить только такой комбинацией.
P.S. в случае с флагами безболезненно заменяется на обычный +, но смотрится не так красиво.

Какие реализации паттерна проектирования “Декоратор” вы знаете?

Хотелось бы узнать о том, как данный паттерн может быть реализован, но не по "стандартной" схеме, предложенной GOF. Привожу пример "стандартной" реализации.
class Component { Component() { ... } } class ConcreteComponent : Component { ConcreteComponent() { ... } } class Decorator : Component { Component c; int newState; public void SetComponent(Component component) { ... } Decorator() { ... } }
Можно ли декорировать объекты как-то по другому, не совмещая агрегацию и наследование, но чтобы при этом сохранялись все преимущества паттерна? Желательно на C#.


Ответ

Я обычно использую декораторы вместе с интерфейсом и композицией.
Например, есть некоторый источник данных о погоде:
public interface IWeatherProvider { public WeatherInfo GetWeather(string city); }
Есть реализация по умолчанию. Например, она ходит по http к провайдеру данных:
public class DefaultWeatherProvider : IWeatherProvider { public WeatherInfo GetWeather(string city) { // обращение по HTTP } }
В некоторых сценариях нам необязательно запрашивать погоду каждый раз у провайдера, а достаточно кэшировать ее:
public class CachingWeatherProvider : IWeatherProvider { private readonly Dictionary _cache; private readonly IWeatherProvider _provider;
public CachingWeatherProvider(IWeatherProvider provider) { _provider = provider; _cache = new Dictionary(); }
public WeatherInfo GetWeather(string city) { WeatherInfo weather; if (!_cache.TryGetValue(city, out weather)) { weather = _provider.GetWeather(city); _cache[city] = weather; } return weather; } }
Используем:
var provider = new CachingWeatherProvider(new DefaultWeatherProvider());
Или вдруг источник ненадежный, часто лежит, и вы захотели добавить ретрай:
public class RetryingWeatherProvider : IWeatherProvider { private readonly IWeatherProvider _provider; private int _maxRetries;
public RetryingWeatherProvider(IWeatherProvider provider, int maxRetries) { _provider = provider; _maxRetries = maxRetries; }
public WeatherInfo GetWeather(string city) { int retry = 0; do { try { return _provider.GetWeather(city); } catch (WebException) { if (retry == _maxRetries) { throw; } else { // подождем немного } } } while (++retry < _maxRetries) } }
И тогда можно наворотить провайдер с кэшем и ретраем:
var provider = new CachingWeatherProvider( new RetryingWeatherProvider(new DefaultWeatherProvider(), 3));
Как именно реализуется декоратор в принципе неважно, отличия имеют право на жизнь. Важно лишь помнить про open-closed принцип: декоратор очень полезен, когда вам нужно расширить функциональность кода, не трогая при этом основной код. У вас есть провайдер данных. Чтобы добавить функциональность ретрая, вы не лезете в основной провайдер, а создаете декоратор. Чтобы добавить кэширование, вы опять же не лезете в провайдер, а создаете еще один декоратор и т.д.
P.S. Весь приведенный код не production ready, а только иллюстрация.

Code First vs Database First

Я почти не имею опыта c EF и собираюсь начать новый проект. Стою перед выбором с чего начать создание доменнной модели с базы или с кода.
В чем преимущества каджого из этих подходов и есть ли они вообще или это вопрос вкуса?


Ответ

диаграмма ниже поможет выбрать подход:
Хороший ресурс для тех кто только начинает изучать EF: Руководство по Entity Framework

Что означает эта конструкция с EventHandler?

VS предложил "упростить"
... EventHandler args = MyHandler if (args != null) { args(this, e); } ...
На
... MyHandler?.Invoke(this, e) ...
Что это значит? Куда копать?


Ответ

В С# 6 появился так называемый null propagation operator. Он позволяет упростить довольно утомительные проверки на null, и означает, что если выражение в его левой части равно null, то он вернёт null, а если оно имеет какое-то другое значение, то будет возвращено значение поля/свойства из правой части, либо будет выполнен метод из правой части. Согласитесь, что писать
data = some?.GetData();
явно удобнее, чем
if(some != null) data = some.GetData();

Как установить шапку группы через VK API?

Для начала вот, что такое шапка группы: В документации API не сказано абсолютно ничего про загрузку. Вылазки через неофициальные клиенты больше не помогают, ибо в них такое не реализовано (отсылка к этому вопросу). Путём просмотра запросов, обнаружил, что сигнатура вызовов не похоже не на один метод/способ загрузки файлов, указанный здесь. Итак, что я смог отрыть из запросов:
У каждого файла, загружаемого на шапку, есть _sig. Он странным образом меняется от запроса к запросу, но без него нельзя загрузить файл. Если отловить запросы вк, то мы получим статическую ссылку для загрузки файла. Эта статическая ссылка вполне себе работает и при переходе на нее пишет такое:
{"error":"ERR_UPLOAD_FILE_NOT_UPLOADED: file not found","bwact":"owner_cover","server":836521,"mid":151665536,"_sig":"83447078c5079124026b80d90f116398"}
Однако после исполнения загрузки в коде, получаем:
{"error":"ERR_UPLOAD_BAD_SIGNATURE","bwact":"owner_cover","server":836521,"_sig":"d762c16dc795c4f65b59aafdaa39628a"}
Метод, используемый VK (обычно метод виден в параметре act. Допустим, при загрузке аудио-сообщения, было add_doc), в документации отсутствует и выглядит так: act=owner_cover


Ответ

Ура! Ура! Ура! Вопрос снова решен :) Правда, сразу скажу, господа, что тут, намного сложнее, чем то, что я решал раньше - тык Внимание: все запросы мы будем производить с cookie. Без них - никак. Вообщем, поехали:
Получаем ссылку для загрузки нашего ковра (в VK шапка называется cover):
Запрос делаем сюда: https://vk.com/al_page.php В headers прикрепляем наши cookie В тело POST-запроса пишем это: act=owner_photo_box&al=1&cover=1&oid=-id вашей группы Если все прошло успешно, получаем примерно такую страницу в ответ: В конце страницы будут ссылки. Нам нужна первая (идет сразу после OwnerPhoto.uploadInit). См. скриншот: Наша ссылка получилась такая: https:\/\/pu.vk.com\/c837731\/upload.php?act=owner_cover&oid=-136618761&square=&mid=151665536&server=837731&_origin=https%3A%2F%2Fvk.com&_sig=c55042259e8ee7c612cdcd9861961cdf Загружаем наше фото на сервера VK, используя ссылку, полученную в предыдущем пункте
Как загрузить файл в формате multipart/form-data я описывал здесь (стандартная библиотека Java) или намного короче и более красиво можно загрузить с помощью библиотеки OkHttp - процесс описан здесь ВНИМАНИЕ: теперь VK принимает картинки только с полем file в post-запросе! Вот так (тут на Java) - multipart.addFilePart("file", uploadFile1); Если картинка будет в поле с другим названием, вы получите такую ошибку:
{"error":"ERR_UPLOAD_FILE_NOT_UPLOADED: file not found","bwact":"owner_cover","server":638219,"mid":151665536,"_sig":"9417bfeb4cca32304ed587818d931931"}
В ответ получим описание нашей фотки в таком формате:
`{"oid":"-136618761","photo":{"photo":"6fae155614x","sizes":[["x","837731536","18af4","9lzKWBYrE2w",795,1060],["y","837731536","18af5","8knjXW2i2K8",810,1080],["o","837731536","18af6","-w20s8JJGNA",810,1080]],"kid":"9d20ccbaa7b6ec6d7171716dcd5bade1","debug":"xxoyooo"},"x_src":"v837731536\/18af4\/9lzKWBYrE2w.jpg","x_size":[795,1060],"size":[810,1080],"bwact":"owner_cover","server":837731,"mid":151665536,"_sig":"fe9a46f1b2e26f4a1c56bbc36850a10e"}`
Сохраняем наше произведение искусства:
Берем первую часть нашей ссылки, полученной в первом пункте с номером сервера, и подставляем к ней act=owner_cover_crop&_query= и описание нашей фотки, полученное из пункта выше. В нашем случае выглядит так:
https://pu.vk.com/c837731/upload.php?act=owner_cover_crop&_query={"oid":"-136618761","photo":{"photo":"2b522d8e86x","sizes":[["x","837731536","18aa5","tuY07_54Ovk",795,497],["y","837731536","18aa6","RxPs7YD5hCs",1590,994],["o","837731536","18aa7","nmZ4LwQDbgw",2880,1800]],"kid":"621fad611afefb9048b478bcc627ab12","debug":"xxoyooo"},"x_src":"v837731536\/18aa5\/tuY07_54Ovk.jpg","x_size":[795,497],"size":[2880,1800],"bwact":"owner_cover","server":837731,"mid":151665536,"_sig":"efb64dcfd413f8e1cd52c86c9ffe98d6"} Это наш URL, к которому будем обращаться.
В header обязательно вставляем наши cookie Ответ получим такой:
{"oid":"-136618761","data":["xAAzIYwAAAAAx7sTQAAGK9PZcylgWKxNsYAAGK9fJJ411totivOAAGK9vsNtLPCSRjQAAAGK91LwRyB-lQoPBAAGK-LTMIdOtvbDACAAGK-W1AR45kIrfADAAGK-n6SOgL5ttKpEAAGK-6ApZsVYFCSa","0,0,795,200",0,"810,1080","795,1060"],"bwact":"owner_cover_crop","server":837731,"mid":151665536,"_sig":"7e008ee2a25eaafe4921763ee3b3691d"} Заставляем VK повиноваться и вставить нашу многострадальную картинку в шапку:
Делаем запрос на этот адрес: https://vk.com/al_page.php Обязательно в headers вставляем cookie В тело POST-запроса вставляем строку, полученную в пункте выше и добавляем перед ней _query=, а после нее - &act=owner_photo_save&al=1&from=groups. Выглядеть тело будет так:
_query={"oid":"-136618761","data":["xAAzIYwAAAAAx7sTQAAGKnqTNf2fQ6fuoYAAGKn3Z9dX-ImPaLOAAGKoG1FCgvWBDhHAAAGKqJRsM9D7RwUzBAAGKqWp6mu7odOTZCAAGKqsVKNMJ80uh9DAAGKq99X4PZhrf1wEAAGKrFjQIUH8hRcw","0,536,2880,724",0,"2880,1800","795,497"],"bwact":"owner_cover_crop","server":837731,"mid":151665536,"_sig":"3aeeb1dff8888aed8bf8f65c91568bb0"}&act=owner_photo_save&al=1&from=groups
Следите за разрешением фото, когда будете его загружать. Если не подойдет - VK начнет обрезать, но вы можете в запросах указать размеры (думаю, понятно где и как). Вообще, VK рекомендует 1590×400...
Спасибо за внимание! Надеюсь кому-то помог...

Конвертирование из object в long

Что я делаю не так:
object j = 149800000; long h = (long)j;
Нужно из object конвертировать в long, в примере выше выходит необработанное исключение типа System.InvalidCastException
Заданное приведение является недопустимым.
Если же в переменную j присвоить большое значение а-ля
object j = 111114082411778; long h = (long)j;
то всё нормально. Также при простом присвоении переменной типа long маленького значения тоже все нормально. Я бы и использовал простой Int32, но вот значения у меня могут быть как маленькие, так и большие, и приходят они в object


Ответ

Нужно в конец добавить суффикс L, так как 149800000 компилятор воспринимает как int
object j = 149800000L; long h = (long)j;
можно еще так
object j = 149800000; long h = (long)(int)j;

Почему некоторые разработчкики записывают числа в 16-ричном представлении? (C#)

Здравствуйте! Достаточно часто в open-source проектах замечаю, что разработчики записывают числа не так:
int i = 2147483647;
А так:
int i = 0x7FFFFFFF;
Даёт это один и тот же результат: у нас имеется переменная, содержащая значение = int.MaxValue, но в чем глубокая логика такой записи? Просто, мол: "Я умею записывать числа в 16-ричном представлении, посмотрите на меня!" Или же тут есть некоторые плюсы? Может, присвоение идет на наносекунды быстрее и/или машине их проще так воспринимать? Разрешите, пожалуйста, мои сомнения по сему поводу!


Ответ

Очевидно, что данное значение инициализатора
int i = 2147483647;
запомнить сложно. Нужно постоянно сверяться со справочником, чтобы правильно выписать все цифры.
Такая запись
int i = 0x7FFFFFFF;
не требует наличия феноменальной памяти.
Но в любом случае было бы проще, лучше и яснее записать
int i = int.MaxValue;
так как такая запись самодокументируемая.
Запись
int i = 0x7FFFFFFF;
предпочтительнее предыдущей записи лишь в одном случае: когда переменная i используется как некоторая маска для битовых операций.