0
votes

I'm having a problem with some of the Assemblies in my FxCop analasys. Most of the assemblies from our project work fine except those for the Api. FxCop just stops analyzing them after 135 messages, with an Exception.

This is the exception details I get.

The following error was encountered while reading module 'TenForce.Execution.Api2.Implementation': Could not resolve member reference: [TenForce.Execution.Api2.Implementation, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]TenForce.Execution.Api2.Implementation.Helpers.IdGenerator1<type parameter.T>+Wrapper1::Object.

I've made sure that all needed assemblies are together and part of the project, but I don't know how to solve this problem. Anyone encountered this before?

  • FxCop 10.0
  • Visual Studio 2010
  • .NET Framework 4
  • TeamCity Test Server

EDIT Adding the source code for the class that's causing the problem:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Collections.ObjectModel;

namespace TenForce.Execution.Api2.Implementation.Helpers
{
    /// <summary>
    /// <para>This class is responsible for generating the various Ids for the Ts.</para>
    /// </summary>
    public static class IdGenerator<T> where T : class, IEquatable<T>, new()
    {
        /// <summary>
        /// Wraps underlying object. Requires object to have int Id property.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public class Wrapper<T> : IEquatable<Wrapper<T>>
        {
            private PropertyInfo piId;

            /// <summary>
            /// Wrapper constructor
            /// </summary>
            /// <param name="instance"></param>
            public Wrapper(T instance)
            {
                Object = instance;
                Created = DateTime.Now;
                foreach (var pi in instance.GetType().GetProperties())
                {
                    if (pi.Name.Equals("id", StringComparison.OrdinalIgnoreCase))
                    {
                        piId = pi;
                    }
                }

                if (piId == null)
                {
                    var fullName = instance.GetType().FullName;
                    throw new TypeInitializationException(fullName,
                        new Exception(string.Format("{0} is not compatible with IdGenerator. It requires int Id property to be present", fullName)));
                }
            }

            /// <summary>
            /// Gets or sets wrapped instance Id
            /// </summary>
            public int Id
            {
                get
                {
                    return (int)piId.GetValue(Object, null);
                }
                set
                {
                    piId.SetValue(Object, value, null);
                }
            }

            /// <summary>
            /// Creation date
            /// </summary>
            public DateTime Created;

            /// <summary>
            /// Wrapped instance
            /// </summary>
            public T Object;

            /// <summary>
            /// Implements IEquatable interface
            /// </summary>
            /// <param name="other"></param>
            /// <returns></returns>
            public bool Equals(Wrapper<T> other)
            {
                return Object.Equals(other.Object);
            }
        }

        #region Private Fields

        private static Wrapper<T>[] _mWrappers = new Wrapper<T>[10];
        private static readonly object MPadLock = new object();

        #endregion

        #region Public Members

        /// <summary>
        /// <para>Generates a new Id for the T and assigns it to the T.</para>
        /// </summary>
        /// <param name="obj">The T that needs a new Id generated.</param>
        /// <remarks>The T will be stored inside the generator to keep track of the Id and availability.</remarks>
        public static void GenerateId(T obj)
        {
            lock (MPadLock)
            {
                // Search the array for an empty spot or an expired T.
                int index = Array.FindIndex(_mWrappers, s => s == null || DateTime.Now.Subtract(s.Created).Minutes > 10);

                var wrapper = new Wrapper<T>(obj);

                // If we found such a spot, store the new T in that location,
                // If we did not find such a spot, expand the array and the T at the end.
                if (index > -1) _mWrappers[index] = wrapper;
                else
                {
                    Array.Resize(ref _mWrappers, _mWrappers.Length + 1);
                    _mWrappers[_mWrappers.Length - 1] = wrapper;
                }

                // Always update the Id of the T entity with the negative index of the entity's location.
                wrapper.Id = CalculateId(Array.IndexOf(_mWrappers, wrapper));
            }
        }

        /// <summary>
        /// <para>Releases the Id generated for the T and releases the location that was held by the T.</para>
        /// </summary>
        /// <param name="obj">The T that needs to be released.</param>
        /// <remarks>The T will be removed from the generator and it's Id will be reset to zero !!!</remarks>
        public static void ReleaseId(T obj)
        {
            lock (MPadLock)
            {
                var wrapper = new Wrapper<T>(obj);
                if (wrapper.Id >= 0) return;
                int index = Array.IndexOf(_mWrappers, wrapper);
                Array.Clear(_mWrappers, index, 1);
                wrapper.Id = 0;
            }
        }

        /// <summary>
        /// <para>Fetches the specified T from the IdGenerator.</para>
        /// </summary>
        /// <param name="id">The unique identifier of the T.</param>
        /// <returns>The T with the matching Id or the default instance if not found.</returns>
        public static T Fetch(int id)
        {
            lock (MPadLock)
            {
                var found = Array.Find(_mWrappers, s => s != null && s.Id == id);
                return found == null ? new T() : found.Object;
            }
        }

        /// <summary>
        /// <para>Updates the matching T entity inside the Generator with the new one.</para>
        /// </summary>
        /// <param name="obj">The T that needs to be updated.</param>
        public static void Update(T obj)
        {
            lock (MPadLock)
            {
                int index = Array.IndexOf(_mWrappers, obj);
                if (index == -1) return;
                var wrapped = new Wrapper<T>(obj);
                _mWrappers[index] = wrapped;
                wrapped.Id = CalculateId(index);
                wrapped.Created = DateTime.Now;
            }
        }

        /// <summary>
        /// <para>Retrieves all the Ts currently available in the application.</para>
        /// </summary>
        /// <returns>An enumerable collection containing all the T entities.</returns>
        public static IEnumerable<T> ListAll()
        {
            lock (MPadLock)
            {
                return new ReadOnlyCollection<T>(_mWrappers.Select(s => s == null ? null : s.Object).Where(o => o != null).ToList());
            }
        }

        #endregion

        #region Private Members

        /// <summary>
        /// <para>Calculates the negative id for an entity based upon the zero-based index.</para>
        /// </summary>
        /// <param name="index">The zero-based index of the entity who's Id needs to be calculated.</param>
        /// <returns>The new Id for the entity.</returns>
        private static int CalculateId(int index)
        {
            return (index * -1) - 1;
        }
        #endregion
    }
}
2
Don't ask us to reverse-engineer source code from an error message. Post a snippet that reproduces this error.Hans Passant

2 Answers

3
votes

There are a couple of known issues that cause this sort of problem: https://connect.microsoft.com/VisualStudio/feedback/details/469754/code-analysis-fails-on-specific-conditions-involving-a-generic-class-containing-an-interface and https://connect.microsoft.com/VisualStudio/feedback/details/520967/code-analyze-brokes-while-loading-interface-from-a-separate-module-file-in-an-indirectly-referenced-assembly. If neither of these seem to apply, could you please provide the following information:

  1. Is TenForce.Execution.Api2.Implementation.Helpers a namespace or a type?
  2. Is IdGenerator<> a class or an interface?
  3. Is IdGenerator<>.Wrapper<> a class or an interface?

Following addition of source code to the question...

The problem is occurring because both IdGenerator<T> and the nested Wrapped<T> class use the same "T" type parameter name. The C# compiler generated a warning (CS0693) for this, which you apparently ignored. If you change the name of the type parameter on the nested class, FxCop should be able to analyze the class correctly (and let you know the rather large number of problems it contains ;).

Incidentally, I would very strongly recommend treating compiler warnings as errors if you're remotely interested in code quality, which you presumably are if you are running FxCop. Why add an additional screening tool before you take maximum advantage of the one you are already using?

1
votes

Just Make sure that the assembly is GAC'd or is present in the same Folder as the assembly you're Analyzing.

Sidenote: You might want to leave out the actual name of the assembly/namespace/method name. Just to be safe and stay out of trouble. If you know what I mean :) *