1

I have two separate methods, where the meat of the method is as follows:

StringBuilder sb = new StringBuilder();
foreach(FooItem I in inventory) 
{
    sb.AppendFormat("{0},{1}…", i.Name, i.Volume);
}

File.WriteAllText(filename, sb.ToString();

So the in one method I have i.Volume, in another it is i.Price. The ONLY difference between the two methods are the property of the object in the list that is being used to output.

So the question is how can I abstract this out where I can tell it which property I want to use in from the given caller?

3 Answers 3

2

You don't need to abstract them, just write one by one using LINQ, usually we don't abstract one-line codes.

var volumeOutput = string.Join("...", volumnObjects.Select(x => $"{x.Name},{x.Volumn}"));
var priceOutput = string.Join("...", priceObjects.Select(x => $"{x.Name},{x.Price}"));

The only difference is your original program has "..." after the last item, I don't know if it's what you want.

1
  • This is slick, and I would go with it, but I have a number of lines of code above and below the segment I gave that are also to be refactored into the method. Will keep this in mind though for other things I have.
    – kw1jybo
    Commented Mar 25, 2019 at 15:37
1

Based on what you said i assume you already have a predefined way of choosing which property to write for a given object.Making this assumption :

class FooItem
{
    public string Name{get;set;}
    public double Volume{get;set;}
}
public void WriteFoos(IEnumerable<(string,FooItem)>inventory,string fileName){
    StringBuilder sb = new StringBuilder();
    foreach(var item in inventory) {
        WriteFoo(item,sb);
    }
    File.WriteAllText(fileName,sb);
}
public void WriteFoo((FooItem item,string property)pair,StringBuilder sb){
      object value=ChooseProperty(pair);
      sb.AppendFormat("{0},{1}", pair.property,value);
}
public object ChooseProperty((FooItem item,string property)pair){
    switch(property){
        case "Volume":return pair.item.Volume;
        case "Name":return pair.item.Name;
    }
}

P.S Choosing the property based on a given string with a switch-case is the most easy way.If you want something generic (without having to write the switch-case you can change the ChooseProperty using System.Reflection like:

public object ChooseProperty((FooItem item,string property)pair){
    PropertyInfo prop=pair.item.GetType().GetProperty(pair.property);
    object value=prop.GetValue(item);
    return value;
}

This however will cause you a performance hit.Another variant is to use System.Linq.Expressions

0

There are other ways of doing this. However, you could use a Func<T,U>

Basically every time you call getProp(item), it will ask for what you passed in the lambda expression`

private void SomeMethod<T>(IEnumerable<Inventory> source, Func<Inventory,T> getProp)
{
   var sb = new StringBuilder();
   foreach(var item in source) 
   {
      sb.AppendFormat("{0},{1}…", item.Name, getProp(item));
   }

   File.WriteAllText(filename, sb.ToString());    
}

Usage

var list = new List<Inventory>();

...

SomeMethod(list, x => x.Volume);
SomeMethod(list, x => x.Price);

Additional Resources

Func Delegate

Encapsulates a method that has one parameter and returns a value of the type specified by the TResult parameter.

Not the answer you're looking for? Browse other questions tagged or ask your own question.