<?php
header('Content-Type: text/html; charset=utf-8');
echo hex2bin('d0bfd180d0b8d0b2d0b5d182');
// текст UTF закодировн в hex чтобы избежать влияния кривых ручек тестировщика/выкрутасов Виндоус
php -S localhost:8081
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
namespace SimpleMessageBus
{
/// <summary>
/// Рассылает события заинтересованным подписчикам
/// в рамках одного приложения.
/// </summary>
/// <remarks>Используются WeakReference, чтобы не было утечек памяти
/// на случай, если кто-то забудет отписаться. Поэтому не рекомендуется
/// использовать лямбда-обработчики событий.</remarks>
public static class MessageBus
{
private static readonly Dictionary<string, List<WeakReference<Action<string, object>>>> Subscribers =
new Dictionary<string, List<WeakReference<Action<string, object>>>>();
/// <summary>
/// Оформляет подписку на событие
/// </summary>
/// <param name="topic">Тип события</param>
/// <param name="handler">Подписчик</param>
public static void Subscribe(string topic,
Action<string, object> handler)
{
if (String.IsNullOrEmpty(topic))
throw new ArgumentNullException(nameof(topic));
if (handler == null)
throw new ArgumentNullException(nameof(handler));
List<WeakReference<Action<string, object>>> handlers;
lock (Subscribers)
if (!Subscribers.TryGetValue(topic, out handlers))
handlers = Subscribers[topic] = new List<WeakReference<Action<string, object>>>();
lock (handlers)
handlers.Add(new WeakReference<Action<string, object>>(handler));
}
/// <summary>
/// Отменяет подписку на событие
/// </summary>
/// <param name="topic">Тип события</param>
/// <param name="handler">Подписчик</param>
public static void Unsubscribe(string topic,
Action<string, object> handler)
{
if (String.IsNullOrEmpty(topic))
throw new ArgumentNullException(nameof(topic));
if (handler == null)
throw new ArgumentNullException(nameof(handler));
List<WeakReference<Action<string, object>>> list;
lock (Subscribers)
if (!Subscribers.TryGetValue(topic, out list))
return;
lock (list)
{
var i = 0;
while (i < list.Count)
{
var reference = list[i];
if (!reference.TryGetTarget(out var target))
list.RemoveAt(i); // Заодно очищаем список от мертвых подписчиков
else if (target == handler)
{
list.RemoveAt(i);
return;
}
}
}
}
/// <summary>
/// Оповещает подписчиков о наступлении события
/// </summary>
/// <param name="topic">Тип события</param>
/// <param name="data">Данные события</param>
public static void Publish(string topic, object data = null)
{
if (String.IsNullOrEmpty(topic))
throw new ArgumentNullException(nameof(topic));
List<WeakReference<Action<string, object>>> list;
lock (Subscribers)
if (!Subscribers.TryGetValue(topic, out list))
return;
var handlers = new List<Action<string, object>>();
lock (list)
{
var i = 0;
while (i < list.Count)
{
var reference = list[i];
if (!reference.TryGetTarget(out var target))
list.RemoveAt(i);
else
{
handlers.Add(target);
++i;
}
}
}
// В Unity вызывать обработчики событий, наверное,
// нужно как-то так:
UnityEngine.WSA.Application.InvokeOnAppThread(() =>
// А в обычном консольном приложении так:
// Task.Run(() =>
{
foreach (var handler in handlers)
{
try
{
handler.Invoke(topic, data);
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
}
}, false);
}
}
}
using System.Diagnostics;
using System.Threading.Tasks;
namespace SimpleMessageBus
{
public static class Program
{
public static async Task Main(string[] args)
{
Debug.WriteLine("Started.");
MessageBus.Subscribe("Rain", RainHandler);
MessageBus.Publish("Rain");
await Task.Delay(100); // Ждем, пока событие поступит
MessageBus.Unsubscribe("Rain", RainHandler);
Debug.WriteLine("Finished.");
}
private static void RainHandler(string topic, object data)
{
Debug.WriteLine("Event: " + topic);
}
}
}
UnityEngine.WSA.Application.InvokeOnAppThread()
— все-таки у нас целевая платформа Unity. иногда есть фризы, например, если открыть пхпшторм, который я уже 2 часа не открывал, или резко перейти с него на фотошоп
AMD или Intel для программиста и (иногда) игрока?
в первом 100 вкладок, во втором 50
как я понимаю если я буду менять значения в Dictionary1 то они будут меняться и в 2 и 3 словарях?
но если я буду менять значения в 2 и 3 словарях они не будут затрагивать друг друга?
то есть меняя значения в 2 словаре это никак не отразится на 3 словарь, я правильно понимаю?
А то просто во недавно столкнулся с такой проблемой что присвоил один словарь другому Dictionary2 = Dictionary1 потом 1й очистил и 2й автоматом тоже оказался очищенным
private Dictionary<string, ClassTest> Dictionary1 // переменная Dictionary1 типа Dictionary<>
= new Dictionary<string, ClassTest>(); //которая ссылается на объект Dictionary [id=1]
private Dictionary<string, ClassTest> Dictionary2 // переменная Dictionary2 типа Dictionary<>
= new Dictionary<string, ClassTest>(); //которая ссылается на объект Dictionary [id=2]
private Dictionary<string, ClassTest> Dictionary3 // переменная Dictionary3 типа Dictionary<>
= new Dictionary<string, ClassTest>(); //которая ссылается на объект Dictionary [id=3]
//Dictionary1 -заполняем данными
Dictionary2 = Dictionary1; //переменная Dictionary2 теперь ссылается туда-же, куда и переменная Dictionary1,
// т.е на Dictionary [id=1]
Dictionary3 = Dictionary1; //переменная Dictionary3 теперь ссылается туда-же, куда и переменная Dictionary1,
// т.е на Dictionary [id=1]
// a объекты Dictionary [id=2] и Dictionary [id=3] будут собраны сборщиком мусора, т.к. они больше не нужны
а как мне сделать 2 словаря по типу 1го, то есть у меня есть 1й словарь шаблон, я хочу чтобы 2й и 3й словари изначально так же и выглядели (имели все те же данные), но далее данные в них менялись независимо друг от друга?
var dict1 = new Dictionary<int, int>()
{
[1] = 2,
};
var dict2 = new Dictionary<int, int>(dict1);
dict1.Add(2, 3);
dict2.Add(2, 1);
var log = new Action<Dictionary<int,int>>((dict) =>
{
Console.WriteLine(string.Join(", ", dict.Select(c => $"{c.Key}={c.Value}")));
});
log(dict1); //1=2, 2=3
log(dict2); //1=2, 2=1