Я еще не нашел идеального ответа, но это близко к решению проблемы.
Напомним, проблема в том, что когда вы передаете метод экземпляра Python в CLR и пытаетесь подключить его ккак делегат, DLR оборачивает сайт вызова целевого объекта другим классом, который действует как промежуточная платформа для вызова динамического события.Теперь это вызывает у нас проблемы, потому что, насколько я могу судить, это делается автоматически на языке и создает новый экземпляр для каждого раза, когда мы пытаемся передать метод экземпляра между CLR и DLR.
Итак, япридумали более приятное решение, чем хранение ссылок на стороне DLR, которое не приведет к утечкам памяти.Предполагается, что он попытается найти аналогичного делегата в текущем списке вызовов.Это выполнит основные проверки, чтобы найти соответствие между переданным делегатом и существующим списком делегатов.Затем, если ничего не найдено, он углубится в базовый код IronPython и покопается, сравнивая несколько вещей.Если он находит совпадение, он удаляет этот экземпляр.
Вот функция: `/// /// Найти существующий делегат, связанный с тем же экземпляром / методом, что и параметр./// /// Это полезно для обхода описанной проблемы http://ironpython.codeplex.com/workitem/30338 /// Делегат для поиска существующей копии (по данным, а не по ссылкам)./// Null, если он не был найден, в противном случае вернуть существующий делегат.внутренняя ActionSignature findDelegate (ActionSignature kInstance) {// Пропустить нулевые данные.if (kInstance == null) возвращает null;
// Otherwise get the invocation list from our multicast delegate.
var lInvocationList = pAction.GetInvocationList();
ActionSignature kExisting = null;
// Do the most basic check (i.e. is our object reference stored in here already!)
if (lInvocationList.Contains(kInstance))
return kInstance;
// Go through and find if one already stored matches our new instance.
foreach (var kIter in lInvocationList)
{
// Cast to our type.
var kIterAS = kIter as ActionSignature;
// Firstly, check our methods are the same. This works for all.
if (kIterAS.Method == kInstance.Method)
{
// Now check the targets match (this way works for IPYs staticmethods and functions).
if (kInstance.Target.Equals(kIterAS.Target))
{
// We matched, so save and break.
kExisting = kIterAS;
break;
}
// Now check if the targets match as instancemethods.
// This is to get around a problem with IronPython where instancemethods
// cannot be removed from CLR delegates. See here:
// http://ironpython.codeplex.com/workitem/30338
var oarr_dd = kIterAS.Target as object[];
var oarr_kh = kInstance.Target as object[];
if (oarr_dd != null && oarr_dd.Length > 0 && oarr_kh != null && oarr_kh.Length > 0)
{
IronPython.Runtime.Method m_dd = oarr_dd[0] as IronPython.Runtime.Method;
IronPython.Runtime.Method m_kh = oarr_kh[0] as IronPython.Runtime.Method;
if (m_dd != null && m_kh != null)
{
if (m_kh.im_self == m_dd.im_self)
{
// We matched, so save and break.
kExisting = kIterAS;
break;
}
}
}
// If we ended up here, we have no match so we can assume this is not the delegate
// we are looking for!
}
}
// Now if our matched delegate is null, it is not found.
return kExisting;
}
`
Надеюсь, это кому-нибудь поможет!:)