Хэш-функция делегата в C # - PullRequest
4 голосов
/ 18 марта 2011

Как я могу получить хэш функции делегата в C #.Я хочу быть в состоянии сказать, отправляются ли различные делегаты в мою функцию.Мой код выглядит примерно так:

public string GetContent(Func<string, bool> isValid)
{
// Do some work
SomeFunctionToHashAFunction(isValid)
}

Я бы использовал .GetHashCode (), но .NET Framework не гарантирует, что они будут уникальными.

РЕДАКТИРОВАТЬ У меня есть кешированный контент, который я проверяю, но я хочу проверить его только один раз.Однако, если функция проверки изменится, мне потребуется повторно проверить кэшированный контент.Я не уверен, будет ли ObjectIdGenerator работать в этом случае, так как мне нужно определить, имеют ли две анонимные функции одинаковую реализацию.

Ответы [ 5 ]

4 голосов
/ 18 марта 2011

По определению хеш не гарантированно является уникальным, поэтому хеширование - это не то, что вам нужно.

Вместо этого вы хотите определить, был ли экземпляр делегата «виден» ранее.Чтобы сделать это, вы можете использовать ObjectIdGenerator:

private static readonly ObjectIdGenerator oidg = new ObjectIdGenerator();

public string GetContent(Func<string, bool> isValid)
{
    bool firstTime;

    oidg.GetId(isValid, out firstTime);

    if (!firstTime)
    {
        ...
    }
}

Однако даже при использовании этой техники есть некоторые подводные камни, о которых следует помнить:

  • ObjectIdGenerator хранит ссылку на каждый объект, который вы передаете ему
  • Делегаты одной и той же функции являются отдельными объектами и поэтому будут возвращать разные идентификаторы

Возможно, если вы объясните что вы пытаетесь достичь, может быть, есть лучший способ сделать это.

РЕДАКТИРОВАТЬ : Учитывая ваши обновленные требования, я бы просто определил валидациюделегировать как собственность.Если свойство изменяется, вы знаете, что вам нужно повторно подтвердить.Поэтому для GetContent() не потребуются никакие параметры:

public Func<string, bool> IsValidHandler
{
    get { return this.isValidHandler; }
    set 
    {
        this.isValidHandler = value;
        this.requiresValidation = true;
    }
}

public string GetContent()
{
    if (this.requiresValidation && this.isValidHandler != null)
    {
        // do validation

        this.requiresValidation = false;
    }

    // return content
}

Вы можете даже упростить процесс и выполнить проверку, когда установлено свойство IsValidHandler (не в методе GetContent).

2 голосов
/ 27 марта 2011

Нет способа (по крайней мере, не совсем хакерского) хешировать анонимную функцию / делегат.Даже если реализация функции одинакова, это может быть закрытием, поэтому результат проверки может отличаться в зависимости от состояния контекста.Рассмотрим следующий пример:

public class Validator
{
    public string SomeState { get; set; }

    public Validator(string someState)
    {
        SomeState = someState;
    }

    public bool IsValid(string input)
    {
        return input == SomeState;
    }
}

// assume your 'input' being validated is "foo"
GetContent((new Validator("foo")).IsValid); // IsValid returns true
GetContent((new Validator("bar")).IsValid); // IsValid returns false

Таким образом, единственный способ убедиться в том, что функция проверки уникальна, состоит в том, чтобы вызывающая сторона определяла уникальность реализации проверки и передавала эту информацию вам.Вам нужно будет переключиться на использование какого-либо интерфейса валидатора, например:

//
// Your code
//

public string GetContent(IValidator validator, 
    IEqualityComparer<IValidator> comparer)
{
    // for tracking used validators, use instance 
    // of 'new HashSet<IValidator>(comparer)'
    // this will give you a hashset of unique validators
}

public interface IValidator
{
    bool IsValid(string input);
}

//
// Your callers code
//

public class Validator : IValidator
{
    // same as Validator class code above
}

public class ValidatorEqualityComparer : IEqualityComparer<Validator>
{
    public bool Equals(Validator v1, Validator v2)
    {
        return GetHashCode(v1) == GetHashCode(v2);
    }

    public int GetHashCode(Validator v)
    {
        int hCode = GetMyStringHash(v.GetType().GUID.ToString() + v.SomeState);
        // as for GetMyStringHash() implementation for this example, 
        // you can use some simple string hashing: 
        // http://www.techlicity.com/blog/dotnet-hash-algorithms.html
        return hCode;
    }
}

Затем вы можете вызвать свой метод следующим образом:

GetContent(new Validator("foo"), new ValidatorEqualityComparer());

Итак, Самая важная часть , на которую следует обратить внимание, это то, что при реализации ValidatorEqualityComparer.GetHashCode() вы используете средство проверки состояния объекта (на основе значения объекта) .Только это обеспечит истинную уникальность логики валидации.

2 голосов
/ 18 марта 2011

Хеши не предназначены быть уникальными. С точки зрения равенства, единственное, для чего вы можете их использовать, - это определить, являются ли два объекта не одинаковыми. Как таковые, они могут быть использованы в качестве быстрого первого теста; если хэши разные, нет смысла делать какие-либо дальнейшие сравнения; два объекта не совпадают. Если хеши do совпадают, объекты могут быть одинаковыми, но они также могут не совпадать, поэтому вам необходимо выполнить более глубокий анализ, чтобы определить равенство.

1 голос
/ 18 марта 2011

Почему бы просто не использовать HashSet для хранения делегатов? Тогда вы можете просто использовать .Contains(isValid), чтобы проверить, был ли делегат уже выдан.

Другими словами, кто-то уже решил эту проблему. Нет причин для вас, чтобы решить это.

0 голосов
/ 18 марта 2011

GetHashCode будет уникальным для разных объектов с коэффициентом 2 ^ 122, что выглядит довольно безопасно.

В противном случае создайте класс, добавьте свойство func и bool, то есть HasBeenSeen.

Должен выполнить работу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...