Posts tagged ‘.Net 4’

C#: ToString To Report all Properties Even Private Ones Via Reflection

At some point one needs to view all the properties of an instance outside of a debugger such as for a unit test reporting the results or possibly a console application informing its status to the output. To achieve the results one overrides `ToString()` and by hand writes the information of the instance’s properties and their values to the output string. This can become cumbersome if the class instance is changing or when one realizes that the time ratio of creating such a reporting operation verses the size of what is being reported can lead to valuable time taken away from the developer.

This article demonstrates a C# extension which will take any class instance and report any non null properties as well as any string lists. The goal of the report is to provide information on the standard properties (string, int, datetime, etc) as well as string lists and ignores any  complex objects. Also provided is the ability to show the non-public properties.

For the resulting visual list, the code lines up the output report in key value pairs where the largest character count key name (the property name reported) will be spaced out along with all other names.

Here is an example result of a class instance with differing properties. Note that `MemberOfAsList` is a List<string> property which internally splits out the property `MemberOf` string (by its comma) into a list. This extension shows the list as a `string__abENT__#46;join` of `__abENT__quot;, __abENT__quot;`.

DistinguishedName : CN=Write Frank,OU=Test,OU=Acme Industries,DC=amce-co,DC=acme,DC=net
CommonName        : Write Frank Lloyd
MemberOf          : CN=2042_Identity,CN=UserIdentities,CN=AlphaVision,DC=acme-co,DC=acme,DC=net
MemberOfAsList    : CN=2042_Identity, CN=UserIdentities, CN=AlphaVision, DC=acme-co, DC=acme, DC=net
otherTelephone    : 303-555-555
Name              : Wright Frank
WhenChanged       : 3/17/2014 9:04:06 PM
LogonCount        : 0

Extension Method

The following is an extension method whose goal is to reflect the type being passed in, determine the sizing of the data for output and then reports the properties each on a different line. String lists values are specified by a `,` (comma and space) separator between each value.

public static string ReportAllProperties<T>(this T instance) where T : class
{

    if (instance == null)
        return string.Empty;

    var strListType = typeof(List<string>);
    var strArrType  = typeof(string[]);

    var arrayTypes   = new[] { strListType, strArrType };
    var handledTypes = new[] { typeof(bool), typeof(Int32), typeof(String), typeof(DateTime), typeof(double), typeof(decimal), strListType, strArrType };

    var validProperties = instance.GetType()
                                  .GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
                                  .Where(prop => handledTypes.Contains(prop.PropertyType))
                                  .Where(prop => prop.GetValue(instance, null) != null)
                                  .ToList();

    var format = string.Format("{{0,-{0}}} : {{1}}", validProperties.Max(prp => prp.Name.Length));

    return string.Join(
             Environment.NewLine,
             validProperties.Select(prop => string.Format(format, 
                                                          prop.Name,
                                                          (arrayTypes.Contains(prop.PropertyType) ? string.Join(", ", (IEnumerable<string>)prop.GetValue(instance, null))
                                                                                                  : prop.GetValue(instance, null)))));
}

Usage

public override string ToString()
{
    return ( this.ReportAllProperties() );
}

Test & Results

var test = new MyClass("Admin") { Name = "Omegaman", 
                                  ID = 1,  
                                  StartDate = DateTime.Now,
                                  AccessPoints = new List<string> { "Alpha", "Beta", "Gamma" },
                                  WeekDays = new string[]{ "Mon", "Tue" }
                                 };

 Console.WriteLine (test.ToString());

/*
Name         : Omegaman
ID           : 1
Role         : Admin
AccessPoints : Alpha, Beta, Gamma
WeekDays     : Mon, Tue
StartDate    : 3/18/2014 12:16:07 PM
*/

....

public class MyClass
{
    public string Name               { get; set; }
    public int ID                    { get; set; }
    private string Role              { get; set; }
    public List<string> AccessPoints { get; set; }
    public string[] WeekDays         { get; set; }    
    public DateTime StartDate        { get; set; }

    public MyClass(string role)
    {
        Role = role;
    }

    public override string ToString()
    {
       return ( this.ReportAllProperties() );
    }

}

Done!

Share

C# Linq: Find Missing Values in a Sequence of Numbers and Other Sequence Related lists as IEnumerable Extensions

Water bubble and wavesI recently had a need to determine if a sequence of integers was solid, not broken, and whether it contained a gap of any missing numbers to report to the end user. I researched the issue and was dismayed that the examples found on the internet seemed to have unnecessary overheads of copied arrays or other artifacts and were too cumbersome for my needs. From that I wrote these C# extensions which work for any .Net above 3.5. Below I document the extension methods to get the missing numbers of a sequence, quickly determine if a sequence is broken and finally report where the existing numbers before the break of the sequence. See the end for the whole extension class for easier copying.

Problem Definition

If one has a set of numbers say

{ 2, 4, 7, 9 }

it has a broken sequence because there are missing numbers from the set 2-9. Those missing numbers are:

{ 3, 5, 6, 8 }

Find Missing Numbers In a Sequence

This method is the one I created first. It uses the Linq Aggregate extension to enumerate over the numbers in the set. If there is a gap which is greater than 1 between the numbers (the difference below is > 0 but same concept) then it reports the numbers missing between the two.

public static IEnumerable<int> SequenceFindMissings(this IList<int> sequence)
{

    var missing = new List<int>();

    if ((sequence != null) && (sequence.Any()))
    {
        sequence.Aggregate((seed, aggr) =>
                            {
                                var diff = (aggr - seed) - 1;

                                if (diff > 0)
                                    missing.AddRange(Enumerable.Range((aggr - diff), diff));

                                return aggr;
                            });
    }

    return missing;
}

Quickly Determine Broken Sequence

Is the sequence broken from the first number to the last in the set?

public static bool IsSequenceBroken(this IEnumerable<int> sequence)
{
    bool broken = false;

    if (sequence != null) 
    {
        var sequenceAsList = sequence.ToList();

        if (sequenceAsList.Any())
        {
            int lastValue = sequence.First();

            broken = sequence.Any(value =>
                                    {
                                        if ((value - lastValue) > 1)
                                            return true;

                                        lastValue = value;

                                        return false;
                                    }); 
        }
    }

    return broken;
}

Report Last Valid Number Before The Break

This is useful in situations where one needs to report where the break happens, say the user is editing in a grid and one highlights the existing number which precedes the missing number(s).

Example here returns a 2 and 5 which are the numbers which precede the break.

   (new List() { 1, 2, 4, 5, 7, 8}).SequenceReportMissingsBreakStarts()

Here is the method:

public static IEnumerable<int> SequenceReportMissingsBreakStarts(this IList<int> sequence)
{

    var breaks = new List<int>();

    if ((sequence != null) && (sequence.Any()))
    {

        sequence.Aggregate((seed, aggr) =>
                            {
                                var diff = (aggr - seed) - 1;

                                if (diff > 0)
                                    breaks.Add(seed);
                                return aggr;
                            });
    }

    return breaks;
}

Full Extension Source With Comments

Here is the code for an easier copy

public static class SequenceExtensions
{
    /// <summary>
    /// Take a sequence of numbers and if there are any gaps greater than 1 between the numbers,
    /// report true.
    /// </summary>
    /// <param name="sequence">A set of numbers to check.</param>
    /// <returns>True if the there is a break in the sequence of numbers.</returns>
    public static bool IsSequenceBroken(this IEnumerable<int> sequence)
    {
        bool broken = false;

        if (sequence != null)
        {
            var sequenceAsList = sequence.ToList();

            if (sequenceAsList.Any())
            {
                int lastValue = sequence.First();

                broken = sequence.Any(value =>
                                        {
                                            if ((value - lastValue) > 1)
                                                return true;

                                            lastValue = value;

                                            return false;
                                        });
            }
        }

        return broken;
    }

    /// <summary>
    /// Take a sequence of numbers and report the missing numbers. Stop at first break found.
    /// </summary>
    /// <param name="sequence">Set of Numbers</param>
    /// <returns>True of sequence has missing numbers</returns>
    public static IEnumerable<int> SequenceFindMissings(this IList<int> sequence)
    {

        var missing = new List<int>();

        if ((sequence != null) && (sequence.Any()))
        {
            sequence.Aggregate((seed, aggr) =>
                                {
                                    var diff = (aggr - seed) - 1;

                                    if (diff > 0)
                                        missing.AddRange(Enumerable.Range((aggr - diff), diff));

                                    return aggr;
                                });
        }

        return missing;

    }

    /// <summary>
    /// A missing break start in a sequence is where the drop off occurs in the sequence.
    /// For example 3, 5, has a missing break start of the #3 for #4 is the missing.
    /// </summary>
    /// <param name="sequence">Set of Numbers</param>
    /// <returns>The list of break numbers which exist before the missing numbers.</returns>
    public static IEnumerable<int> SequenceReportMissingsBreakStarts(this IList<int> sequence)
    {

        var breaks = new List<int>();

        if ((sequence != null) && (sequence.Any()))
        {

            sequence.Aggregate((seed, aggr) =>
                                {
                                    var diff = (aggr - seed) - 1;

                                    if (diff > 0)
                                        breaks.Add(seed);
                                    return aggr;
                                });
        }

        return breaks;

    }
}

Hope this helps!

Share

Asp.Net C#: Upgrading Website to Latest Version Gotchas and How to Resolve

iStock_000015438998XSmallOne can get lost in the weeds when upgrading an asp.net .Net 1 website to anything from .Net 2 through .Net 4.  One of the biggest problems after the initial conversion is that when built each page or control throws a build error:

Could not load type ‘MyNamespace.myWebPage’.

The issue stems from the fact that things changed, made life easier for new projects, and namespaces which were required were removed and certain attributes changed. To resolve the above issue follow these steps presented in this article.

In the code behind file

  1. Remove the namespace scope. In the example below remove the highlighted lines:
    namespace MyNamespace
    {
        public class myWebPage : System.Web.UI.Page {}
    }
  2. Add the modifier partial to the class definition to make it look like this
    public partial class myWebPage : System.Web.UI.Page { ... }

In the aspx File

Which initially looks like this:

<%@ Page language="c#" AutoEventWireup="false"
                       Codebehind="myWebPage.aspx.cs"
                       Inherits="MyNamespace.myWebPage" %>
  1. Change the attribute Codebehind to CodeFile.
  2. Remove the namespace from the value found in the attribute Inherits.

The result should look like this:

<%@ Page language="c#" AutoEventWireup="false"
                       Codefile="myWebPage.aspx.cs"
                       Inherits="myWebPage" %>
Share

C# Open Word Documents using Visual Studio 2010 and .Net 4

With VS2010 and .Net 4, working with the office interops has become a lot easier. This article gives a step by step view of how to open a word document without needing the tools of Visual Studio Tools for Office (VSTO). *

The following topics are demonstrated:

  1. Open and properly close a Word Document.
  2. Write to a Word document.
  3. Remove the Word document’s meta data.
  4. Properly close the Word Application and clean up resources opened by the underlying Office Interop calls.
  5. Properly cast method calls to specific interops to avoid “Ambiguity between method” issue CS0467 C# compiler warning.
  6. Why the developer no longer has to reference null when passing in optional parameters to COM objects thanks to .Net 4.

Steps

  1. In VS2010 create a Console Application.
  2. In the Solutions Explorer right click on the References folder and select Add Reference.  In the .Net tab search for
    Microsoft.Office.Interop.Word.
    Note you can use version 12 or version 14; but you might as well use the latest 14.  
  3. Insert the following usings:
    using Microsoft.Office.Interop.Word;
  4. Create an existing Word document. The example code below uses an existing document at C:\TestDoc.docx.
  5. Insert this code:
    Application ap = new Application();
    
    try
    {
    
        Document doc = ap.Documents.Open( @"C:\TestDoc.docx", ReadOnly: false, Visible: false );
        doc.Activate();
    
        Selection sel =  ap.Selection;
    
        if ( sel != null )
        {
            switch ( sel.Type )
            {
                case WdSelectionType.wdSelectionIP:
                    sel.TypeText( DateTime.Now.ToString() );
                    sel.TypeParagraph();
                    break;
    
                default:
                    Console.WriteLine( "Selection type not handled; no writing done" );
                    break;
    
            }
    
            // Remove all meta data.
            doc.RemoveDocumentInformation( WdRemoveDocInfoType.wdRDIAll );
    
            ap.Documents.Save( NoPrompt: true, OriginalFormat: true );
    
        }
        else
        {
            Console.WriteLine( "Unable to acquire Selection...no writing to document done.." );
        }
    
        ap.Documents.Close( SaveChanges: false, OriginalFormat: false, RouteDocument: false );
    
    }
    catch ( Exception ex )
    {
        Console.WriteLine( "Exception Caught: " + ex.Message ); // Could be that the document is already open (/) or Word is in Memory(?)
    }
    finally
    {
        // Ambiguity between method 'Microsoft.Office.Interop.Word._Application.Quit(ref object, ref object, ref object)' and non-method 'Microsoft.Office.Interop.Word.ApplicationEvents4_Event.Quit'. Using method group.
        // ap.Quit( SaveChanges: false, OriginalFormat: false, RouteDocument: false );
        ( (_Application)ap ).Quit( SaveChanges: false, OriginalFormat: false, RouteDocument: false );
    
        System.Runtime.InteropServices.Marshal.ReleaseComObject( ap );
    }

Explanation

  • Line 1: Open Word application object found in the Microsoft.Office.Interop.Word namespace.
  • Line 6: Open up the Word document we are interested in. This is first instance of using named parameters in calling the underlying COM functionality.
  • Line 7: Activate makes sure our document has focus in the event that Word is already open.
  • Line 9-17: This code is a template to working with a selection and its type. Word distinguishes areas of interest by selections. Our selection is at the beginning of the document. When we get the selection we write the current date and time (line 16).
  • Line 27: Remove all of the meta data of the document. This is not required for writing, just as an added bonus of how-to.
  • Line 29: Save what we have done.
  • Line 37: Close the document.
  • Line 48: In line 47 if we call without the cast we get the ambiguity warning message from the compiler. By casting to the Application interface we avoid that warning.
  • Line 50: Release any COM handles or resources we may have inadvertently gotten in this process.

 

* For the record VSTO is only needed when we are creating a smart document or an addin to one of the office applications. This is pure interop programming and not VSTO.

Share

SQL Server SP1 Setup: Does it really need a beta version of .Net 4?

BabyWaitingI  upgraded my development box to Windows 7 and ignored, whistled past the graveyard as it were, the warning that SQL Server 2008 should be uninstalled due to incompatibilities. Upon the new OS install/upgrade I ventured out and tried to bring up the management studio. Much to my chagrin it crapped out on me, ya chagrin thats it.

So with that darned internet so handy I researched came to the conclusion, from the advice of the internet millions that SP1 should be installed to get it to work on Windows 7. Here is what greeted me for my efforts once as I attemped install:

SP1 2008

Maybe you are reading this in the future where there is a flying car in every drive way and hanging a television on a wall is really passé because the wall is a TV; but as of this writing .Net 4 is only in beta.

So here is the text (a little trick which one can do is that on most dialogs one can do CTRL-C and get the text copied to the clipboard) as received:

—————————
setup.exe – .NET Framework Initialization Error
—————————
To run this application, you first must install one of the following versions of the .NET Framework:

  v4.0.20506

Contact your application publisher for instructions about obtaining the appropriate version of the .NET Framework.

So I leave it up to you my small but loyal (?) readership what is going on? Here is what I know

  1. Upgraded from Vista to Windows 7.
  2. Visual Studio 2010 version is installed but doesn’t run. So there is a version of .Net 4 on my system…
    NetVersions
  3. It all worked before I upgraded. ;-)

Thoughts?

Share

Tribal Knowledge: Large Object Heap and Double Arrays in .Net

(Update 4/3/2011: .Net 4 Relevancy)

In the .Net world when objects are greater than 85 thousand bytes they are generally placed in the Large Object Heap (LOH). But there is a caveat to that and certain objects are placed in the LOH way before 85K. The one situation I detail here in this blog is the double array which goes in way sooner.

Don’t believe me? Try this code snippet:

byte[] Lesthan85K = new byte[84987];
byte[] At85K = new byte[85000];

Console.WriteLine("Lesthan85K:     " + GC.GetGeneration(Lesthan85K)); // 0
Console.WriteLine("At85K:          " + GC.GetGeneration(At85K));      // 2

double[] array999Double = new double[999];

Console.WriteLine("array999Double: " + GC.GetGeneration(array999Double)); // Returns 0

double[] array1Kdouble = new double[1000];

Console.WriteLine("array1Kdouble:  " + GC.GetGeneration(array1Kdouble)); // Returns 2

By looking at the garbage collection generation, we can identify if objects reside the LOH or not. If it is generation 2 then bingo we are in the LOH!

What we see is that a double array resides in the LOH way before the 85 thousand byte yardstick. I had reported this as a bug to Microsoft connect  Large Object Heap (LOH) does not behave as expected for Double array placement and was told; this is by design.

It appears that because of performance issues, it is better to insert the double arrays earlier due to the fact that the LOH is aligned in 8 byte increments. This allows better access to those large arrays in normal code processing and the tradeoff point was 1 thousand doubles and was implemented in .Net that way.

That is my piece of Tribal Knowledge that I pass on to you…use it wisely.

Update for .Net 4 and 64 Bit and Future Versions of .Net

Recently I got a chance to explore why this had not changed for .Net 4 and the realm of 64 bit computing when I was at the Microsoft Campus talking to some of the people on the CLR team.  One of the Senior Project Managers who works with the CLR team at Microsoft Andrew Pardoe was kind enough to provide this clarification that things are still the same for .Net 4 and 64 bit applications for arrays of 1000 doubles; but that may change going forward:

The CLR’s execution engine aggressively attempts to place these arrays on the LOH because of the performance benefit of accessing aligned doubles. However, there’s no benefit to applying this heuristic on 64-bit architectures because doubles are already aligned on an 8-byte boundary.

Thank you for bringing this to my attention. We’ve made changes to this heuristic that should appear in a future release of the .NET Framework.

Share