Resident Zero9999
Resident Zero9999

Reputation: 113

How to pass pre-defined functions as a parameter of another function?

I have two classes: TextElement that is a selenium extension with some text properties (Text returns the string of the element) and the other is ArrayTextElement that basically is an array of TextElement objects.

/// <summary>
/// Finds the first element that matches the text
/// </summary>
public static TextElement Find(this ArrayTextElement<TextElement > list, string text)
{
    try
    {
        return list.Items.First(item => item.Text.Equals(text));
    }
    catch (Exception)
    {
        throw new NotFoundException($"Requested element with text: '{text}' wasn't found.");
    }
}

/// <summary>
/// Finds the first element that contains the text
/// </summary>
public static TextElement FindByContains(this ArrayTextElement<TextElement > list, string text)
{
    try
    {
        return list.Items.First(item => item.Text.Contains(text));
    }
    catch (Exception)
    {
        throw new NotFoundException($"Requested element with text: '{text}' wasn't found.");
    }
}

The real issue is that I need to unify those 2 functions into 1. So I want to send the Equals and Contains functions that extend from String, as a parameter.

Upvotes: 0

Views: 81

Answers (3)

holly_cheng
holly_cheng

Reputation: 2481

If I understand you correctly, you can pass an additional parameter to indicate if you want to use an exact match or a partial. The following is good if you the only searches you want to do are exact or partial. The other answers given here are far more versatile, but this version is a little easier to maintain.

public static TextElement Find(this ArrayTextElement<TextElement> list, string text, bool exactMatch)
{
    try
    {
        return list.Items.First(item => exactMatch ? 
            item.Text.Equals(text) :
            item.Text.Contains(text)
         );
    }
    catch (Exception)
    {
        throw new NotFoundException($"Requested element with text: '{text}' wasn't found.");
    }
}

To use it:

TextElement textElem = list.Find("abcdef", [true|false]);

Upvotes: 1

JSteward
JSteward

Reputation: 7091

You can refactor both methods into one by passing a Func<string, bool> and using that function inside your first. So what you have now becomes:

public static TextElement Find(this ArrayTextElement<TextElement> list, Func<string, bool> predicate)
{
    try
    {
        return list.Items.First(item => predicate(item.Text));
    }
    catch (Exception)
    {
        throw new NotFoundException($"Requested element with text: '{text}' wasn't found.");
    }
}

And to call it with either Contains or Equals you would do this:

public void UsingTheMethod()
{
    ArrayTextElement<TextElement> list = new ArrayTextElement<TextElement>();
    string someText = string.Empty;
    Find(list, s => s.Equals(someText));
    Find(list, s => s.Contains(someText));
}

Upvotes: 3

germi
germi

Reputation: 4658

You can simply pass a Func<string, bool> like so:

public static TextElement Find(this ArrayTextElement<TextElement> list, Func<string, bool> predicate)
{
    try
    {
        return list.Items.First(item => predicate(item.Text));
    }
    catch (Exception)
    {
        throw new NotFoundException($"Requested element with text: '{text}' wasn't found.");
    }
}

And call it like this:

var text = // whatever;
var element = elements.Find(s => s.Equals(text));

Upvotes: 2

Related Questions