Click here to Skip to main content
12,448,563 members (54,806 online)
Click here to Skip to main content
Add your own
alternative version

Stats

5K views
3 bookmarked
Posted

How To Set Elements Of An Array Of A Private Type Using Visual Studio Shadows

, 15 Apr 2010 CPOL
Rate this:
Please Sign up or sign in to vote.
How To Set Elements Of An Array Of A Private Type Using Visual Studio Shadows

Visual Studio uses Publicize to create accessors public for private members and types of a type.

But when you try to set elements of a private array of elements of a private type, things get complicated.

Imagine this hypothetic class to test:

free hit counters
public static class MyClass
{
    private static readonly MyInnerClass[] myArray = new MyInnerClass[10];

    public static bool IsEmpty()
    {
        foreach (var item in myArray)
        {
            if ((item != null) && (!string.IsNullOrEmpty(item.Field)))
            {
                return false;
            }
        }

        return true;
    }

    private class MyInnerClass
    {
        public string Field;
    }
}

If I want to write a test for the case when the array has “non empty” entries, I need to setup the array first.

Using the accessors generated by Visual Studio, I would write something like this:

[TestClass()]
public class MyClassTest
{
    [TestMethod()]
    public void IsEmpty_NotEmpty_ReturnsFalse()
    {
        for (int i = 0; i < 10; i++)
        {
            MyClass_Accessor.myArray[i] = 
		new MyClass_Accessor.MyInnerClass { Field = i.ToString() };
        }

        bool expected = false;
        bool actual;

        actual = MyClass.IsEmpty();

        Assert.AreEqual(expected, actual);
    }
}

But the test will fail because, although the elements of the private array myArray can be read as MyClass_Accessor.MyInnerClass instances, they can't be written as such.

To do so, the test would have to be written like this:

[TestClass()]
public class MyClassTest
{
    [TestMethod()]
    public void IsEmpty_NotEmpty_ReturnsFalse()
    {
        for (int i = 0; i < 10; i++)
        {
            MyClass_Accessor.ShadowedType.SetStaticArrayElement
		("myArray", new MyClass_Accessor.MyInnerClass 
		{ Field = i.ToString() }.Target, i);
        }

        bool expected = false;
        bool actual;

        actual = MyClass.IsEmpty();

        Assert.AreEqual(expected, actual);
    }
}

But, this way, we lose all the strong typing of the accessors because we need to write the name of the array field.

Because the accessor for the field is a property, we could write a set of extension methods that take care of getting the field name for us. Something like this:

public static class PrivateypeExtensions
{
    public static void SetStaticArrayElement<T>
	(this PrivateType self, Expression<Func<T[]>> expression, 
	T value, params int[] indices)
    {
        object elementValue = (value is BaseShadow) ? 
		(value as BaseShadow).Target : value;

        self.SetStaticArrayElement(
            ((PropertyInfo)((MemberExpression)(expression.Body)).Member).Name,
            elementValue,
            indices);
    }

    public static void SetStaticArrayElement<T>
	(this PrivateType self, Expression<Func<T[]>> 
	expression, BindingFlags invokeAttr, T value, params int[] indices)
    {
        object elementValue = (value is BaseShadow) ? 
		(value as BaseShadow).Target : value;

        self.SetStaticArrayElement(
            ((PropertyInfo)((MemberExpression)(expression.Body)).Member).Name,
            invokeAttr,
            elementValue,
            indices);
    }
}

Now, we can write the test like this:

[TestClass()]
public class MyClassTest
{
    [TestMethod()]
    public void IsEmpty_NotEmpty_ReturnsFalse()
    {
        for (int i = 0; i < 10; i++)
        {
            MyClass_Accessor.ShadowedType.SetStaticArrayElement(() => 
		MyClass_Accessor.myArray, new MyClass_Accessor.MyInnerClass 
		{ Field = i.ToString() }, i);
        }

        bool expected = false;
        bool actual;

        actual = MyClass.IsEmpty();

        Assert.AreEqual(expected, actual);
    }
}

It’s not the same as the first form, but it’s strongly typed and we'll get a compiler error instead of a test run error if we change the name of the myArray field.

You can find this and other tools on the PauloMorgado.TestTools on CodePlex.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Paulo Morgado
Software Developer (Senior) Paulo Morgado
Portugal Portugal

You may also be interested in...

Pro
Pro

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.160811.3 | Last Updated 15 Apr 2010
Article Copyright 2010 by Paulo Morgado
Everything else Copyright © CodeProject, 1999-2016
Layout: fixed | fluid