Home > Back-end >  Write generic function for either string or my custom type
Write generic function for either string or my custom type

Time:10-26

I have the following two extension methods. (I have a lot more, but I'll use these for this discussion.)

public static MyExtensions
{
    public static int IndexOf(this string s, Func<char, bool> predicate, int startIndex)
    {
        for (int i = startIndex; i < s.Length; i  )
        {
            if (predicate(s[i]))
                return i;
        }
        return -1;
    }

    public static int IndexOf(this StringEditor s, Func<char, bool> predicate, int startIndex)
    {
        for (int i = startIndex; i < s.Length; i  )
        {
            if (predicate(s[i]))
                return i;
        }
        return -1;
    }
}

They both do the same thing. One works with type string. And the other works with type StringEditor, which is a class I created.

My question is if anyone can think of a way to implement both in a single method using generics.

I cannot modify string, but I can make any changes needed to StringEditor.

I cannot derive StringEditor from string because string is sealed.

I couldn't find any interface implemented by string for accessing individual characters that I could implement in StringEditor. IEnumerable<T> is available but does not support accessing individual characters directly like an array.

And it isn't valid to make a type argument for both string and StringEditor.

public static int IndexOf<T>(this T s, Func<char, bool> predicate, int startIndex) where T : string, StringEditor

I don't think this can be done. But maybe someone is more clever than me?

Update

Where I described that I needed to directly access individual characters, I meant using the s[i] syntax. In addition to generally being less performant, IEnumerable<T> does not support this.

While IEnumerable<T> could be used to perform the results of my two methods here, it does not allow direct character access.

CodePudding user response:

Generics not needed. Use IEnumerable<char>, which is implemented by String and could be implemented by your StringEditor.

public static int IndexOf(this IEnumerable<char> s, Func<char, bool> predicate, int startIndex) 
{
    int i = startIndex;
    foreach (char c in s.Skip(startIndex))
    {
        if (predicate(c))
            return i;
        i  ;
    }
    return -1;
}

Or

public static int IndexOf(this IEnumerable<char> source, Func<char, bool> predicate, int startIndex) 
{
    var s = source.ToArray();
    for (int i = startIndex; i < s.Length; i  )
    {
        if (predicate(s[i]))
            return i;
    }
    return -1;
}

CodePudding user response:

Since you said you needed indexed access for other methods of this kind, you can define a wrapper around string for that and use an implicit typecasting operator for that wrapped class. This might be more expensive than what you're willing to save, but it's possible:

public interface IIndexedChar
{
     char this[int index] { get; }
     int Length { get; }
}

public struct IndexedString : IIndexedChar {
  public string Value { get; }
  public IndexedString(string value) => Value = value;
  public this[int index] => Value[index];
  public int Length => Value.Length;
  static implicit operator IndexedString(string s) => new IndexedString(s);
}

// implement the same interface in your type too

and write your functions like this:

public static int IndexOf(this IIndexedChar s, Func<char, bool> predicate, int startIndex)
{
    for (int i = startIndex; i < s.Length; i  )
    {
        if (predicate(s[i]))
            return i;
    }
    return -1;
}
  • Related