Posts Tagged Lambda calculus

C# Short Takes – 2 – String from IEnumerable


Introduction

I am posting this quick tip in response to a question, which seems to on some people’s minds who are reading my blog. The search terms ‘create string from ienumerable’ appear as hits on my blog statistics quite frequently. The way I create a string from an IEnumerable is in the Example Code section below.

The Method

The method I use to create a string from an IEnumerableis to use the string constructor that accepts a char[] (see the MSDN documentation: String Constructor (Char()) ). To get the IEnumerable into a char[] I use the Linq Extension Method ToArray() (see the MSDN documentation: Enumerable.ToArray(Of TSource) Method).

These Linq method call and string constructor results in the code in the ‘Example Code’ section.

The Example Code

The following shows a number of ways to create an IEnumerableobject. These IEnumerableobjects are then converted into char[] object. The char [] objects are then used in the string constructor.

private void String_Create_From_IEnumerable_char( )
{
    string TestString = "The quick red fox jumped over the lazy brown cow";
    IEnumerable<char> EnumerableChar= TestString.AsEnumerable();
    string Result1 = new string(EnumerableChar.ToArray( ));
    char[] TestCharArray = new char[] { 'T', 'h', 'e', ' ', 't', 'e', 's', 't', ',', 'v', 'a', 'l', 'u', 'e', '.' };
    string Result2 = new string(TestCharArray);
    IEnumerable<char> EnumerableChar1 = TestCharArray.AsEnumerable( );
    string Result3 = new string(EnumerableChar1.ToArray());
    IEnumerable<char> EnumerableChar2 = LINQ_Extension_Methods.LINQ_Extension_Methods.ToIEnumerable('A')
        .UnionAll(LINQ_Extension_Methods.LINQ_Extension_Methods.ToIEnumerable('B'))
        .UnionAll(LINQ_Extension_Methods.LINQ_Extension_Methods.ToIEnumerable('C'))
        .UnionAll(LINQ_Extension_Methods.LINQ_Extension_Methods.ToIEnumerable('D'))
        .UnionAll(LINQ_Extension_Methods.LINQ_Extension_Methods.ToIEnumerable('E'));
    string Result4 = new string(EnumerableChar2.ToArray( ));
    Func<char, IEnumerable<char>> LocalToIEnumerable1 = LINQ_Extension_Methods.LINQ_Extension_Methods.ToIEnumerable<char>;
    IEnumerable<char> EnumerableChar3 = LocalToIEnumerable1('Z')
        .UnionAll(LocalToIEnumerable1('Y')).UnionAll(LocalToIEnumerable1('X')).UnionAll(LocalToIEnumerable1('W'))
        .UnionAll(LocalToIEnumerable1('V')).UnionAll(LocalToIEnumerable1('U')).UnionAll(LocalToIEnumerable1('T'));
    string Result5 = new string(EnumerableChar3.ToArray( ));
    Func<char, char, IEnumerable<char>> LocalToIEnumerable2 = LINQ_Extension_Methods.LINQ_Extension_Methods.ToIEnumerable<char>;
    IEnumerable<char> EnumerableChar4 = LocalToIEnumerable2('A', ' ')
        .UnionAll(LocalToIEnumerable2('B', ' ')).UnionAll(LocalToIEnumerable2('C', ' '))
        .UnionAll(LocalToIEnumerable2('D', ' ')).UnionAll(LocalToIEnumerable2('E', ' '))
        .UnionAll(LocalToIEnumerable2('F', ' ')).UnionAll(LocalToIEnumerable2('G', ' '))
        .UnionAll(LocalToIEnumerable2('H', ' ')).UnionAll(LocalToIEnumerable2('I', ' '));
    string Result6 = new string(EnumerableChar4.ToArray( ));
    return;
}

Methods Referenced That Are Not In The.Net Framework

Method Blog Post That Describes The Method
ToIEnumerable LINQ Extension Method to Generate n-way Cartesian Product
UnionAll LINQ Short Takes – Number 4 –Make Union into a UnionAll

Conclusion

I trust that those readers who have been looking for a solution to this transformation find this blog post helpful answers the question you had.

, , , , , , , ,

3 Comments

Dumping a formatted IEnumerable to Output


Introduction

This blog post is a continuation from the preceding post LINQ Extension Method To Dump any IEnumerable. This blog post presents another LINQ extension method, which addresses, and provides a solution to, the limitations of the preceding approach. The significant limitation of the preceding approach was that the return type of the method was a string. This returned string runs the risk of overflowing a strings capacity when the IEnumerablehas a large number of elements, and/or the object to be output generates large amounts of formatted output.

This blog post presents a method that has the intention of taking an IEnumerable and pushing the contained objects to an output facility. The types of output facility utilised should be user defined. Personally, I use the Debug Output Window (see: Diagnostic Messages in the Output Window), and text files. I expect that this method will support, through the design and implementation of the extension method, support any output facility.

The ToOutput Extension Method

Introduction

Design Goals

This extension method attempts to achieve two sets of design goals. These design goals were:

Design Goals from the ToPrintString Implementation
The method uses an unconstrained type parameter to describe the objects in the input IEnumerable.
The method uses an unconstrained type parameter to describe the objects in the input IEnumerable,
The method consumes Lambda Expressions, or delegates, to supply user-defined functionality.
The method used optional parameters for the parameters that supply used defined functionality.
The method supplies meaningful default actions for any omitted parameter.
  • Improve on the efficiency and flexibility of the previous method (the ToPrintString extension method presented in by blog post LINQ Extension Method To Dump any IEnumerable ) and remove the potential limitation on the maximum size of a string. The design goals to achieve this aim were:
Enable the emitting of each object in the IEnumerable directly to the output target.
Enable an output function is as flexible as possible.
The output function must accept a Lambda Expression, or a delegate.
Have a return from the function that will not suffer any possible overflow, or out of memory, system runtime exceptions.

Method Implementation – The Function Signature

The implementation of the ToOutput extension method has the following function signature.

public static long ToOutput<TSource>(this IEnumerable<TSource> Input,
    Func<TSource, int, bool> WherePredicate = null,
    Func<TSource, int, string> FormatFunction = null,
    Func<string, bool> OutputFunction = null,
    bool SummaryCount = true)

The function signature has the following features that address the design goals:

  • As with the ToPrintString extension method, the type that the type parameter TSource will accept has no constraints. This maximises the type of object that this extension method will accept.
  • The argument Input is the attribute of the function signature that makes this method an extension method. Specifically, allows the compiler to make the extension method association between this extension method and the interface type IEnumerable of T. The interface IEnumerable of T is the interface that the LINQ extension methods manipulate.
  • All of the extension method arguments are options, apart from the mandatory Input argument.
  • The arguments FormatFunction and OutputFunction supply a meaningful default implementation if the argument is null.
  • The arguments WherePerdicate and FormatFunction use an int argument. This int value is the position of the object in the input IEnumerable.
  • As with the ToPrintString extension method, this extension accepts a WherePerdicate argument. This argument allows the methods caller to specify a Lambda Expression, or delegate, which will select the objects in the Input IEnumerable processed by the extension method.
  • The argument OutputFunction is one of the additions to the ToOutput over the ToPrintString extension method. The LINQ extension method LongCount invokes argument OutputFunction. The use of the LongCount LINQ extension method is why the return type of the Lambda Expression, or delegate, is a bool. This result is indicating success, or failure, of the output operation.
  • The function argument SummaryCount controls the writing of a summary count through the OutputFunction. This may be useful if the output destination is a UI control.

Method Implementation – The Full Method Implementation

The following is the implementation of the ToOutput extension method.

For those who would like the source code in a file, I have loaded the code as a Word Document (.docx format) and a PDF to:
https://craigwatson1962.files.wordpress.com/2012/02/tooutput_cs1.docx , and
https://craigwatson1962.files.wordpress.com/2012/02/tooutput_cs1.pdf .
I hope that readers who want to use the source code for this method will find this an acceptable way of sharing the source. It should be a simple copy and paste operation to load this code into Visual Studio, or your C# preferred development environment. These files also include the xml comments (see: XML Documentation Comments (C# Programming Guide) for further information) for the method. These xml comments will enable IntelliSense (see: Using IntelliSense for further explanation) for the method extension.

public static long ToOutput<TSource>(this IEnumerable<TSource> Input,
    Func<TSource, int, bool> WherePredicate = null,
    Func<TSource, int, string> FormatFunction = null,
    Func<string, bool> OutputFunction = null,
    bool SummaryCount = true)
{
    if (FormatFunction == null)
        FormatFunction = (InputObject, Position) =>
            string.Format("[{1}] {0}, ", Position, InputObject);
    if (OutputFunction == null)
        OutputFunction = (StringRepesentation) =>
        {
            Debug.Write(StringRepesentation);
            return true;
        };
    long ElementsDone = 0L;
    if (WherePredicate == null)
    {
        ElementsDone = Input
            .Select((InputObject, Position) => FormatFunction(InputObject, Position))
            .LongCount((StringRepesentation) => OutputFunction(StringRepesentation));
    }
    else {
        ElementsDone = Input
            .Where((InputObject, Position) => WherePredicate(InputObject, Position))
            .Select((InputObject, Position) => FormatFunction(InputObject, Position))
            .LongCount((StringRepesentation) => OutputFunction(StringRepesentation));
    }

    if (SummaryCount)
    {
        string OutputCount = string.Format("\nObjects Processed = {0:#,#}\n", ElementsDone);
        bool done = OutputFunction(OutputCount);
    }
    return ElementsDone;
}

Method Implementation – Noteworthy Features

The following are notable elements in the implementation:

  • This extension method uses the LINQ method syntax to invoke extension methods the processing pattern.
  • The diagram below shows the LINQ methods composed to form the processing pattern used by this extension method. This extension method’s processing pattern is a series of LINQ method calls that pass the callers delegates to the LINQ implementation.

  • The use of Debug.Write as a default action for the OutputFunction is my choice for the most appropriate default action for my development efforts. If the reader has other thoughts on the matter, they are more than welcome to install their preference.

Sample Code Invoking the ToOutput Extension Method

The sample code demonstrates a series of calls to the ToOutput extension method. The sample code demonstrates calls to the ToOutput extension method that all use the LINQ method call syntax.

At present, I cannot think of how to use this extension method in the LINQ query syntax. The reason for that inability is that in the design of this method. This method’s design characterises a ‘data sink’. I would call something a ‘data sink’ if it is a process just that consumes an IEnumerable(of T) and does not produce a sequence.

The pattern of consume an IEnumerable(of T) and produce an IEnumerable(of T) would characterise a ‘transformation’. Methods that conform to the ‘transformation’ pattern are inherently linkable into chains of processes.

The following are links to the sample code stored in docx and PDF formats.
https://craigwatson1962.files.wordpress.com/2012/02/simpletoprintstringtests_cs.docx
https://craigwatson1962.files.wordpress.com/2012/02/simpletoprintstringtests_cs.pdf

Conclusions

There a couple of thoughts I will raise in conclusion of the presentation of the ToOutput extension method. The thoughts include:

  • The development of LINQ extension method may appear daunting when you initially look at the topic. This is probably due to the syntax that the C# language requires to build an extension method is unfamiliar. I believe, and hopefully this and the proceeding blog posts demonstrates, that when you overcome that initial hurdle, implementing extension methods is not a significantly difficult process.
  • The use of Lambda Expressions or delegates to arguments to the extension methods is a very powerful and flexible implementation approach. This approach allows the abstraction between the pattern of processing and the actions applied at each step in the process. The extension method supplies the pattern of processing. The Lambda Expressions or delegates supply the caller-defined actions. This approach has much in common with functional programming approaches (see: Functional Programming topic in Wikipedia for an introduction to the topic).
  • This extension method does implement a solution that addresses, and resolves, the issue identified with the preceding blog post (LINQ Extension Method To Dump any IEnumerable). The strategy of writing directly to the output facility through the user supplied delegate, results in an implementation with a minimal memory requirement. Specifically, there is no dependence on the string object. This results in an implementation that cannot exceed the string objects finite capacity constraints.
    I have not evaluated whether this implementation is thread safe. A significant part the multi-thread safety of this extension method is dependent on the user’s implementation of the delegates passed into the extension method. The input delegates will need to be multi-thread safe to invoke this extension method the following fashion. The following is just one alternative for invoking this method in a parallel fashion.
    NB: This uses a “sledgehammer” to force parallel execution. The inclusion of the calls to AsUnordered() and WithDegreeOfParallelism(8) forces parallel execution, which is not what the ‘smarts’ in the implementation wants to do.
var Test1 = from counter1 in Enumerable.Range(0, 10000)
            select counter1;
var List1 = Test1.ToList();
var a = List1.AsParallel<int>().AsUnordered().WithDegreeOfParallelism(8).ToOutput(
    FormatFunction:
        (objValue, position) =>
            string.Format("[{0}] {1}\n", position, objValue));

The following the Parallel Stacks screen snippet, shows the multiple treads. In addition, the output comes out in a nicely unordered sequence, indicating parallel threads are in action.

, , , , , , , , , , , ,

4 Comments

LINQ Extension Method To Dump any IEnumerable


Introduction

I have been doing some development with LINQ recently, and will present some of the generally useful LINQ Extension methods in this (and some forthcoming blog posts).

This post will focus on the most generally useful LINQ extension methods I have developed. These methods produce a formatted dump the contents of a sequence (IEnumerableto be precise).

These methods have evolved to their current through the application of the DRY Principle (Don’t Repeat Yourself). I was finding that I was writing very similar code to dump the contents of LINQ result sequences repeatedly. The repetitions of very similar code through the project lead me to developing these extension methods.

The Class Defining the Extension Methods

The C# compiler that implements the rules for defining the implementation of Extension Methods is very pedantic. The containing class must be marked as static. The requirements for the implementation of extension methods are described in Extension Methods (C# Programming Guide) .The following is the class definition which I have been using to contain the LINQ extension method.

    public static class LINQ_Extensions 

The full version of the class definition, with comments, which result in IntelliSense context sensitive help being generated is as follows:

    /// <summary> /// Class which supplies LINQ extension Methods. /// Extension methods are: /// <see cref="Window"/>, /// <see cref="AllValuesDistinct"/>, /// ToPrintString"/>, /// <see cref="ToIntegralValue"/>, /// <see cref="ToBigIntValue"/>. /// </summary> public static class LINQ_Extensions 

Failure to mark the class as static will result in the compiler error CS1106.

error CS1106: Extension method must be defined in a non-generic static class

Introducing The ToPrintString LINQ Extension Method

This is the first of a pair of LINQ extension methods I will present. This method is the one I first implemented. The second extension method I will resent here is very similar to this method, but addresses some of the limitations that this method contains. The most significant limitations of this implementation I will detail further on in this bog post.

ToPrintString – Design Decisions

The design of this extension method needed to enable a number of features. These design features included:

1) I wanted external control over a couple of points in the processing of this extension method. These points of control accept Lambda Expressions, enabling the caller to supply the functionality that is required.

2) I wanted the extension method to work with any type of object. Hence, the use of a generic type parameter to the implementation (see: Introduction to Generics (C# Programming Guide) for further information).

3) The type parameter for this implementation should not be constrained. Hence, it will work with declared stucts, declared classes, and anonymous classes (see Anonymous Types (C# Programming Guide) for further information).

4) I wanted a simple signature to the extension method. This desire lead me to implement the method using Optional Parameters (see: Named and Optional Arguments (C# Programming Guide)) with Default Values that provide a useful (in my opinion) implementation. This desire should (and has) resulted in an implementation that can be invokes with no arguments.

5) I wanted the flexibility to select the elements of the sequence are dumped. To achieve this wanted to have a where predicate, like the LINQ Where method, as part of the implementation.

6) I wanted to have all of the information which LINQ can supply available. The particular piece of information that I wanted available was the position in the sequence each object occupies.

ToPrintString – Implementation Decisions

The decisions made in the implementation fall into two groups. These groups are the implementation decisions that support, or implement, the design goals, and those which support an efficient and effective implementation. The following is the signature for the implementation of the extension method.

public static string ToPrintString<TSource>(
    this IEnumerable<TSource> InputSequence,
    Func<TSource, int, bool> WherePredicate = null,
    Func<TSource, int, string> FormatFunction = null,
    Func<StringBuilder, string, StringBuilder> ConcatenateFunction = null)

Implementation Features Supporting The Design Goals

The signature of the extension method implements a number of the design goals for the method. These design goals and implementations include:

1) The three Func< arguments expose the points in the method where the caller of the method can supply custom functionality. This satisfies the goal of allowing the caller to supply functionality that is required.

2) The parts of the function’s signature that utilises the <TSource> type parameter enables the flexibility to apply the extension method to any type of object contained in a sequence.

3) The function signature does not contain any type parameter constraints (see: Constraints on Type Parameters (C# Programming Guide) ). This further enables the flexibility of the method, allowing application to any type.

4) The three Func< arguments to the method are declared with a default a value of null. This allows the method to be invoked using .ToPrintString() call. I will write more about the use of null as a default value further in this blog post.

5) The method argument Func<TSource, int, bool> WherePredicate = null, enables the capability to apply a logical expression to select objects from the sequence. The signature that is utilised for the WherePredicate is same signature as the LINQ Where extension method.

6) The int arguments to the Func<TSource, int, bool> WherePredicate and Func<TSource, int, string> FormatFunction is position in the sequence that the object occupies. This is a base zero number.

Implementation Features Decisions Supporting An Effective Implementation

There are a couple of implementation choices within the implementation. These choices attempt to achieve the most efficient, and effective, implementation. These choices include:

· The FormatFunction and ConcatenateFunction provide useable, and for me useful default values, if the argument is null. See below (The Implementation of ToPrintString) for the default values implemented.

· The extension method uses the LINQ Extension Method Aggregate to perform the output, or resulting, string concatenation. The Aggregate extension method seems to be the clearest expression of intent in forming the output from the extension method.

· The Aggregate method uses a StringBuilder object to assemble the result. The use of the StringBuilder object results in a more efficient implementation when compared with just concatenating String Objects (in general, and when the size of the output string can get large).

The Implementation of ToPrintString

The following is the implementation of the ToPrintString extension method.

/// <summary> /// Builds a printable string from the enumerable. /// /// <typeparam name="TSource">Type of the source object contained in the enumerable. ///InputSequence">The enumerable which is formatted for printing. /// ///WherePredicate">[Optional] A where predicate used to select the objects to be output.<br/> /// Predicate signature: /// <code>FuncInputObject, int PositionInSquence, bool ReturnValue></code> /// Predicate Arguments: /// <list type="number"> /// <item><description>[Input Parameter] <br/> /// The object from the input sequence. <br/> /// The type of the object is the same as the declaration of the sequence.<br/> /// For compound sequences like Dictionary the object is a KeyValuePair. /// </description></item> /// <item><description>[Input Parameter] <br/> /// The position in the input sequence which object occupies. /// This is a base zero number.</description></item> /// <item>><description>[Return Parameter] <br/> /// Indicates if the object should be selected (true case) or excluded (false case). /// /// /// /// ///FormatFunction">Optional. A formatting function which will convert /// the position in the sequence and the object into a string value.<br/> /// Predicate Signature: /// <code>FuncInputObject, int PositionInSquence, bool ReturnValue></code> /// Predicate Arguments: /// <list type="number"> /// <item>[Input Parameter] The object from the input sequence. <br/> /// The type of the object is the same as the declaration of the sequence.<br/> /// For compound sequences like Dictionary the object is a KeyValuePair.</item> /// <item>[Input Parameter] The position in the input sequence which object occupies. /// This is a base zero number.<br/> /// If a where clause is used and rejects objects, /// then this number is the position in the result of the where clause sequence. /// </item> /// <item>[Return Parameter] The required string representation of object .</item> /// <item>[Default Value}<br/>The following is used if FormatFunction argument is null. /// <code>(Source, Position) => string.Format("[{0}] {1}", Position, Source);  /// /// ///ConcatenateFunction">[Optional]<br/> /// A function which concatenates the string versions of the object into one string.<br/> /// Predicate Signature: /// <code>Func<StringBuilder ResultString, string ObjectStringValue, StringBuilder ReturnValue></code> /// Arguments: /// <list type="number"> /// <item>[Input Parameter]<br/> /// The StringBuilder object which is used to collect the input object formatted strings.</item> /// <item>[Input Parameter]<br/>T /// he string representation of the object, generated by the FormatFunction.</item> /// <item>[Returns Parameter]<br/>StringBuilder result from the ConcatenationFnuction.</item> /// <item>[Default Value]<br/>This is used if ConcatenationFunction argument is null. /// <code>ConcatenateFunction = (Result, Value) => Result.AppendFormat(" {0}", Value);</code> /// </item> /// </list> /// </param> /// <returns>String of formatted and concatenated values.</returns> /// <remarks> /// This extension method can potentially exceed the maximum capacity of the string object. /// </remarks> /// <example> /// <code>// Simple tests case - no function arguments /// string output = "Test1".ToPrintString(); /// Debug.WriteLine( /// string.Format("Characters in Test1 = {0}", output)); /// </code> /// </example> public static string ToPrintString<TSource>(
    this IEnumerable<TSource> InputSequence,
    Func<TSource, int, bool> WherePredicate = null,
    Func<TSource, int, string> FormatFunction = null,
    Func<StringBuilder, string, StringBuilder> ConcatenateFunction = null)
{
    if (FormatFunction == null)
        FormatFunction = (Source, Position) => string.Format("[{0}] {1}", Position, Source);
    if (ConcatenateFunction == null)
        ConcatenateFunction = (Result, Value) => Result.AppendFormat(" {0}", Value);
    StringBuilder retVal;
    if (WherePredicate == null)
    {
        retVal = InputSequence
            .Select((a, pos) => FormatFunction(a, pos))
            .Aggregate(new StringBuilder(),
            (ReturnString, Value) => ConcatenateFunction(ReturnString, Value));
    }
    else {
        retVal = InputSequence
            .Where((InputObject, Position) => WherePredicate(InputObject, Position))
            .Select((InputObject, Position) => FormatFunction(InputObject, Position))
            .Aggregate(new StringBuilder(),
            (ReturnString, Value) => ConcatenateFunction(ReturnString, Value));
    }
    return retVal.ToString();
}

Examples of code calling the ToPrintString Extension Method

The following is a method that demonstrates a number of invocations of the extension method ToPrintString. I hope that it shows the main ways that this method could be invoked.

private void SimpleToPrintStringTests()
{
    // Simple tests case - no function arguments string output = "Test1".ToPrintString();
    Debug.WriteLine(
        string.Format("Characters in Test1 = {0}", output));

    // Declaring a simple array int[] SimpleArray = new int[] { 1, 2, 3, 4 };
    // Test Against an array with no arguments. output = SimpleArray.ToPrintString();
    Debug.WriteLine(
        string.Format("Simple 4 Element int array {0}", output));
    // Supplying a where clause output = SimpleArray.ToPrintString((val, pos) => val % 2 == 0);
    Debug.WriteLine(
        string.Format("Simple 4 Element int array, with a where clause {0}", output)); ;
    // Supplying an optional argument for the Format Function output = SimpleArray.ToPrintString(FormatFunction: (val, pos) => val.ToString());
    Debug.WriteLine(
        string.Format(
        "Simple 4 Element int array, with an optional Format Function argument\n{0}" , output)); ;
    // Supplying a optional argument for the Concatenation Function output = SimpleArray.ToPrintString(
        ConcatenateFunction: (carry, val) => carry.AppendFormat("{0}, ", val));
    Debug.WriteLine(
        string.Format(
        "Simple 4 Element int array, with an optional Concatenation Function argument\n{0}" , output));
    // Declaring a where predicate Func<int, int, bool> WherePredicate =
        (InputObject, Position) =>
        {
            if (Position % 2 == 0)
                return false;
            return true;
        };
    // Supplying a where predicate as a externally declared function output = SimpleArray.ToPrintString(WherePredicate);
    Debug.WriteLine(
        string.Format(
        "Simple 4 Element int array, with a Where Predicate argument declared externally\n{0}" , output));

    // Declaring a list of objects List<Tuple<int, string>> SimpleObjects = new List<Tuple<int, string>>()
    {
        Tuple.Create(1, "Test"),        Tuple.Create(200, "String Test"),
        Tuple.Create(-21, "Testing"),   Tuple.Create(0, "the quick brown")
    };
    // External Where Predicate Func<Tuple<int, string>, int, bool> Where1 =
        (obj, pos) =>
        {
            if (obj.Item1 >= 0) return true;
            else return false;
        };
    // External Format Predicate Func<Tuple<int, string>, int, string> Format1 =
        (obj, pos) => string.Format(
            "[{0}] int value={1} string value ={2}\n" , pos, obj.Item1, obj.Item2);
    // Calling using external declared predicates output = SimpleObjects.ToPrintString(Where1, Format1);
    Debug.WriteLine(
        string.Format("Processing a list of object with external predicates\n{0}" , output));
    // Another where predicate Func<Tuple<int, string>, int, bool> Where2 =
        (obj, pos) =>
        {
            if (obj.Item1 < 0) return true;
            else return false;
        };
    // Calling using external declared predicates output = SimpleObjects.ToPrintString(Where2, Format1);
    Debug.WriteLine(
        string.Format("Processing a list of object with external predicates 2\n{0}" , output));

    // A more complex object collection to test against Dictionary<long, int?> DictTest = new Dictionary<long, int?>()
    {
        { 234L, null },         {-44345L, 65742 },
        { -5644, null },        {6799032L, 8765464 }
    };
    // Supplying where and format as more complex inline lambda expressions output = DictTest.ToPrintString((dictObj, pos) => dictObj.Value.HasValue,
        (dictObj, pos) =>
            string.Format("Key={0} Value={1}\n", dictObj.Key, dictObj.Value.Value));
    Debug.WriteLine(
        string.Format("Processing a dictionary with inline lambda expressions\n{0}" , output));
    // A format function for a dictionary. // NB: You need to unwrap the Dictionary into passed KeyValuePair objects. // Also, lambda capture of the Dictionary Object to supply the Count property. Func<KeyValuePair<long, int?>, int, string> Format2 =
        (dictObj, position) =>
        {
            if (dictObj.Value.HasValue)
                return string.Format("Object {0} of {1} Key = {2} Value = {3}\n",
                    position, DictTest.Count(), dictObj.Key, dictObj.Value);
            else return string.Format("Object {0} of {1} Key = {2} Value = null\n",
                    position, DictTest.Count(), dictObj.Key);
        };
    output = DictTest.ToPrintString(FormatFunction: Format2);
    Debug.WriteLine(
        string.Format(
        "Processing the KeyValPair objects with named external function\n{0}" , output));
    return;
}

Limitations Of The Implementation

There is one significant limitation of is implementation the use of a string as the return type. The string object has a finite (but quite large) limit on the length of the string that can be stored in the object. A sequence with many elements, and/or a large amount of information formatted per object, could exceed the maximum size of a string. The System.String documentation says that this limit is about 2GB (or about 2 billion characters); a character count is not possible because the characters of the string are stored as Unicode characters (which can be multiple bytes per character).

Mechanically, or within the string class, the finite limit on the size of the string is probably the maximum positive value of an Int32, or 2,147,483,647 characters, and 2GB of memory. The System.String uses Int32 as arguments to many methods and properties, and probably internally as well. This dependence on the Int32 is why I would conclude the finite limit for the class would be the value of Int32.MaxValue (or 2,147,483,647).

In a subsequent blog post, probably the next blog post, I will detail another extension method that addresses this limitation.

Conclusions

There are a number of points that I should are worthy of noting. These concluding remarks include:

· Building this extension method was not particularly difficult.

· The use of the Func<> object takes a bit of getting used to. There are plenty of examples showing how to use it in the .Net framework library.

· The Func<> object does not allow for more information that in the method signature than shown above. The use and meaning of the arguments has to come in the supporting documentation for the method.

· The use of a default value of null for the optional Func<> arguments is all C# seems to allow. This is probably a design decision made in the definition of language.

, , , , , , , , , ,

1 Comment

%d bloggers like this: