[英]How to ensure a method logic is executed only once per arguments combination?
我正在設計一個類庫,它有一堆類型的方法“EnsureXXX”。 只要調用代碼需要某些東西而不需要特定於參數的初始化,就會調用此方法的思想。 它類似於ASP.Net的EnsureChildControls
方法,但使用參數作為鑒別器。
例如:
public static class SomeUtilityClass {
public static void EnsureSomething(string arg1, int arg2, object arg3)
{
// Logic should be called once for each args combination
}
}
public class CallerClass
{
public void Foo()
{
SomeUtilityClass.EnsureSomething("mycustomerid", 4, myData.SomeProperty);
}
public void Foo2()
{
SomeUtilityClass.EnsureSomething("mycustomerid", 4, myData.SomeProperty);
}
}
因為這樣的模式將在幾個地方重用並經常調用,所以我必須將性能作為目標。 我還必須有一個線程安全的方法。
為此,我寫了一個小實用程序類:
public sealed class CallHelper
{
private static readonly HashSet<int> g_YetCalled = new HashSet<int>();
private static readonly object g_SyncRoot = new object();
public static void EnsureOnce(Type type, Action a, params object[] arguments)
{
// algorithm for hashing adapted from http://stackoverflow.com/a/263416/588868
int hash = 17;
hash = hash * 41 + type.GetHashCode();
hash = hash * 41 + a.GetHashCode();
for (int i = 0; i < arguments.Length; i++)
{
hash = hash * 41 + (arguments[i] ?? 0).GetHashCode();
}
if (!g_YetCalled.Contains(hash))
{
lock (g_SyncRoot)
{
if (!g_YetCalled.Contains(hash))
{
a();
g_YetCalled.Add(hash);
}
}
}
}
}
消費代碼如下所示:
public static class Program
{
static void Main()
{
SomeMethod("1", 1, 1);
SomeMethod("2", 1, 1);
SomeMethod("1", 1, 1);
SomeMethod("1", 1, null);
Console.ReadLine();
}
static void SomeMethod(string arg1, int arg2, object arg3)
{
CallHelper.EnsureOnce(typeof(Program), ()=>
{
Console.WriteLine("SomeMethod called only once for {0}, {1} and {2}", arg1, arg2, arg3);
}, arg1, arg2, arg3);
}
}
正如預期的那樣輸出:
SomeMethod called only once for 1, 1 and 1
SomeMethod called only once for 2, 1 and 1
SomeMethod called only once for 1, 1 and
我有一些與此方法相關的問題:
HashSet<int>
和我計算哈希的方法是否正確? 我特別想知道null
處理是否正確,以及我是否可以通過這種方式“哈希”一個Action
委托。 提前致謝
這基本上是一個memoize ,除了你的函數是無效的。 但是,對輸入參數進行比較的相同考慮因素仍然有效。
Wes Dyer討論了如何在這篇文章中創建一個通用的多參數memoize 。 一般的想法是將所有參數都轉換為匿名類型,並將其用作字典鍵。
關於使這個線程安全,請考慮.NET已經有並發集合 。 您不需要將非並發集合轉換為並發集合; 只需使用提供的集合。
為了使這個方法適用於沒有泄漏的實例方法,要么將WeakReference保留給實例,要么將memoizer的實例存儲在實例本身中,無論哪種方法都適合您。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.