0

As the title says I'm trying to create a linq extension method that allows me to run a function on just one of an objects properties, unfortunately I've not made it very far on this and all I really have is (what I believe) is the shell of a method to do this:

 public static IQueryable<T> ChangeProperty<T>(this IQueryable<T> source, Expression<Func<T, string>> selector, Func<T,T> method)
    {
        //Placeholder
        return Enumerable.Empty<T>().AsQueryable();
    }

For context, I have this function which strips all html elements out of a string:

public static string RemoveUnwantedTags(string data)
    {
        if (string.IsNullOrEmpty(data)) return string.Empty;

        var document = new HtmlDocument();
        document.LoadHtml(data);

        var acceptableTags = new string[] { "strong", "em", "u" };

        var nodes = new Queue<HtmlNode>(document.DocumentNode.SelectNodes("./*|./text()"));
        while (nodes.Count > 0)
        {
            var node = nodes.Dequeue();
            var parentNode = node.ParentNode;
            if (acceptableTags.Contains(node.Name) || node.Name == "#text") continue;
            var childNodes = node.SelectNodes("./*|./text()");

            if (childNodes != null)
            {
                foreach (var child in childNodes)
                {
                    nodes.Enqueue(child);
                    parentNode.InsertBefore(child, node);
                }
            }
            parentNode.RemoveChild(node);
        }

        var htmlFormattingTags = new [] {"&nbsp;","&tbsp;"};
        if (!htmlFormattingTags.Any(x=>document.DocumentNode.InnerText.Contains(x))) return document.DocumentNode.InnerHtml;

        var template = document.DocumentNode.InnerText;
        foreach (var tag in htmlFormattingTags)
        {
            template = template.Replace(tag, " ");
        }
        return template;
    }

I'm grabbing data using EF, and I'll need this function for 4 different tables (hence wanting to make it generic). So if I have say this class:

public partial class EmailTemplate : INotifyPropertyChanging, INotifyPropertyChanged
{
    private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty);

    private int _ID;
    private string _tenant;
    private string _TemplateName;
    private bool _HTML;
    private string _Body;
    private string _Images;
    private string _Subject;
    private System.Nullable<bool> _SMS;
    private System.Guid _rowguid;
    private System.Nullable<int> _OverrideServer;

^^ Truncated because it's an EF class

I want to be able to do

dc.EmailTemplates
    .Where(x=>x.Body != null)
    .ChangeProperty(x=>x.Body, RemoveUnwantedTags)
    .ToList();
Nkosi
  • 235,767
  • 35
  • 427
  • 472
Coffee
  • 392
  • 3
  • 16
  • While the above is not that hard (should take you a good hour and afterwards you understand expressions roughly), the thing you try to archive, is not how IQueryable works and yields you only one thing: Exceptions. – X39 Oct 17 '19 at 11:31
  • @X39 thanks for the reply, I'm just starting to get more in depth with generics and expressions and presumed that when making Linq extensions it would need to be an IQueryable method. How would I make this without using IQueryable? – Coffee Oct 17 '19 at 11:35
  • I'm guessing I'd use IEnumerable instead since iQueryable implements it? – Coffee Oct 17 '19 at 11:39
  • 1
    You just use IEnumerable, correct. For your method itself, refer to eg. https://stackoverflow.com/questions/2055927/ienumerable-and-recursion-using-yield-return as you do not really need any expressions here. Just reassign the value in your method and yield-return it afterwards – X39 Oct 17 '19 at 11:40
  • I'll take a look through that, thanks! – Coffee Oct 17 '19 at 11:42

1 Answers1

0

You could just call t.Body = RemoveUnwantedTags(t.Body) on each element.

dc.EmailTemplates
    .Where( t => t.Body != null)
    .ToList()//Load from db
    .ForEach( t => t.Body = RemoveUnwantedTags(t.Body)) //This is done in memory, not in the database
tymtam
  • 31,798
  • 8
  • 86
  • 126
  • I was trying to use this to learn generics and extension methods, but I appreciate that this is a clean easy solution to the problem! – Coffee Oct 17 '19 at 12:03