6

Suppose I want to write an extension method to dump some data from a T[,] to a CSV:

public static void WriteCSVData<T>(this T[,] data, StreamWriter sw)
{
    for (int row = 0; row < data.GetLength(0); row++)
        for (int col = 0; col < data.GetLength(1); col++)
        {
            string s = data[row, col].ToString();

            if (s.Contains(","))
                sw.Write("\"" + s + "\"");
            else
                sw.Write(s);

            if (col < data.GetLength(1) - 1)
                sw.Write(",");
            else
                sw.WriteLine();
        }
}

which I could call with

using (StreamWriter sw = new StreamWriter("data.csv"))
  myData.WriteCSVData(sw);

but suppose myData is a Complex[,] and I want to write the magnitude of the complex number, not the full value. It would be handy if I could write:

using (StreamWriter sw = new StreamWriter("data.csv"))
  myData.WriteCSVData(sw, d => d.Magnitude);

but I'm not sure how to implement that in the extension method or if it's even possible.

1
  • Don't forget to quote any quotes or newlines in your output fields! Commented Sep 15, 2014 at 6:50

2 Answers 2

8

You can write an overload of your existing method like this:

public static void WriteCSVData<T, TValue>(this T[,] data, StreamWriter sw, 
    Func<T,TValue> func)
{
    for (int row = 0; row < data.GetLength(0); row++)
        for (int col = 0; col < data.GetLength(1); col++)
        {
            string s = func(data[row, col]).ToString();

            if (s.Contains(","))
                sw.Write("\"" + s + "\"");
            else
                sw.Write(s);

            if (col < data.GetLength(1) - 1)
                sw.Write(",");
            else
                sw.WriteLine();
        }
}

and use it the way you wanted:

using (StreamWriter sw = new StreamWriter("data.csv"))
    myData.WriteCSVData(sw, d => d.Magnitude);
Sign up to request clarification or add additional context in comments.

2 Comments

-1, Your for loop version generates a new line for each row, while your LINQ version generates a new line for each element.
@Gabe you're right. I must have overlooked that it only writes a new line for the last element of a row. removed.
1

Define a delegate with parameter type T and return type string. Add a parameter to method WriteCSVData with type the delegate.

delegate string ExtractValueDelegate<T>(T obj);

public static void WriteCSVData<T>(this T[,] data,ExtractValueDelegte<T> extractor , StreamWriter sw) { ... }

// calling the method
 myData.WriteCSVData(sw, d => d.Magnitude.ToString());

1 Comment

There is no need for "manual delegates" anymore. .NET has them built in now - Func<T, string> in this case...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.