Account Options

  1. Sign in
The old Google Groups will be going away soon, but your browser is incompatible with the new version.
Google Groups Home
« Groups Home
Problem (and resolution) when using the C5 generic collection library
There are currently too many topics in this group that display first. To make this topic appear first, remove this option from another topic.
There was an error processing your request. Please try again.
flag
  2 messages - Collapse all  -  Translate all to Translated (View all originals)
The group you are posting to is a Usenet group. Messages posted to this group will make your email address visible to anyone on the Internet.
Your reply message has not been sent.
Your post was successful
 
From:
To:
Cc:
Followup To:
Add Cc | Add Followup-to | Edit Subject
Subject:
Validation:
For verification purposes please type the characters you see in the picture below or the numbers you hear by clicking the accessibility icon. Listen and type the numbers you hear
 
Bob  
View profile  
 More options Feb 10 2010, 11:00 am
From: Bob <b...@ntlworld.com>
Date: Wed, 10 Feb 2010 08:00:31 -0800 (PST)
Local: Wed, Feb 10 2010 11:00 am
Subject: Problem (and resolution) when using the C5 generic collection library
Hi Ted,

Thanks for a brilliant class. Since you have taken the time to put
this together and test it I thought it only fair to share a suggested
modification with you and others. First let me add some context.

The C5 Generic Collection Library is produced and published by the IT
University of Copenhagen who describe it thus:

C5 is a library of generic collection classes for C# and other CLI
languages and works with Microsoft .Net version 2.0 and later, and
Mono version 1.2 and later.

C5 provides functionality and data structures not provided by the
standard .Net System.Collections.Generic namespace, such as persistent
tree data structures, heap based priority queues, hash indexed array
lists and linked lists, and events on collection changes. Also, it is
more comprehensive than collection class libraries on other similar
platforms, such as Java. Unlike many other collection class libraries,
C5 is designed with a strict policy of supporting "code to interface
not implementation".

I have been using this library because of its superior performance and
its ability to generate events when various actions are performed on a
collection.

I experienced a problem using this library with JsonExSerializer which
triggered an unhandled "Ambiguous Match Exception" during the
serialization process. After giving some consideration to seeing how
easy it would be to implement a custom collection handler for the
serialisation of this object and searching the site for information on
how to do this the thought struck me that the serializer was reporting
(indirectly via the exception) not that it didn't understand about the
C5 classes but that at some critical point it either couldn't or
didn't distinguish between the standard generic collection types and
their C5 counterparts.

After tracing through the code the problem area was quickly
established. Not surprisingly it lies in the current implementation of
the GenericCollectionHandler class so no banana there! I want on to
modify the code slightly in order to better understand why it was
failing and to see if anything could be done without affecting the
integrity of it.

I found that with two relatively straight forward modifications the
problem could be easily resolved. If you accept these mods you may, of
course, want to implement them slightly differently or tighten up on
the error checking.

The first mod concerns the IsCollection() method, which is where the
exception was being thrown.
In the original code below the call to collectionType.GetInterface
failed because the C5 collection contained
two references that matched the _IGenericCollectionName, one with a C5
namespace and one with the standard generic collections namespace.

        public override bool IsCollection(Type collectionType)
        {
            return (!collectionType.IsArray
                    &&
collectionType.GetInterface(_IGenericCollectionName) != null
                    && !
_IDictionaryType.IsAssignableFrom(collectionType));
        }

It occurred to me that at this point the check is only to see if the
interface exists not whether multiples can be resolved. To this end I
modified the code to

        public override bool IsCollection(Type collectionType)
        {
            bool isCollection = false;
            if (!collectionType.IsArray)
            {
                if (SupportsInterface(collectionType,
_IGenericCollectionName))
                {
                    if (!
_IDictionaryType.IsAssignableFrom(collectionType))
                    {
                        isCollection = true;
                    }
                }
            }
            return isCollection;
        }

The nested 'if' statements came about out of the need to identify
which part of the test was failing and why so these could now be
collapsed again if so desired. The middle condition has been changed
to call a new function called 'SupportsInterface' given below. This
version will return true if one *or more* matches against the given
interface can be made.

        private bool SupportsInterface(Type collectionType, string
interfaceType)
        {
            bool interfaceSupported = false;
            try
            {
                interfaceSupported =
(collectionType.GetInterface(interfaceType) != null);
            }
            catch (AmbiguousMatchException ambiguousMatch)
            {
                // Ambuguity means that the interface is supported.
Whether the ambiguity can be resolved is
                // not relevant at this point
                interfaceSupported = true;
            }
            return interfaceSupported;
        }

This allowed the serialization process proceed further to the point
where a specific instance of the interface needs to be obtained in the
GetItemType() method. The solution adopted here is to obtain an array
containing the matching interfaces and then find the one whose
namespace matches that of the given object. Whilst this approach may
not be foolproof in all cases (I will pass that on to you for
consideration), it certainly solved the problem for my particular
case.

The original code

        public override Type GetItemType(Type CollectionType)
        {
            Type intfType =
CollectionType.GetInterface(_IGenericCollectionName);
            return intfType.GetGenericArguments()[0];
        }

has been modified to replace the call to GetInterface() with a call to
FindInterfaces() which returns an array of matching items. The array
is then scanned for an entry whose interface namespace matches that of
the given object.

        public override Type GetItemType(Type CollectionType)
        {
            Type interfaceType = null;

            // Set up a filter to obtain the all of interfaces that
match _IGenericCollectionName
            TypeFilter typeFilter = new
TypeFilter(CollectionInterfaceFilter);
            Type[] types = CollectionType.FindInterfaces(typeFilter,
_IGenericCollectionName);

            // Find the entry with a namespace that matches the given
collection
            foreach (Type type in types)
            {
                if (type.Namespace == CollectionType.Namespace)
                {
                    interfaceType = type.GetGenericArguments()[0];
                }
            }

            return interfaceType;
        }

The creation of a TypeFilter requires a helper to perform the actual
check.

        public static bool CollectionInterfaceFilter(Type type, object
filterCriteria)
        {
            return type.Name == filterCriteria.ToString();
        }

With these changes in place I can now serialize and deserialize a
C5.LinkedList object that resides alongside a standard Dictionary and
ArrayList (for test purposes). I haven't been able to run your unit
tests against these mods at this stage as my test setup is somewhat
different.

I hope this is of help to you and other users of the serializer.

Regards
Bob Bellchambers-Wilson


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Ted Elliott  
View profile  
 More options Feb 12 2010, 2:06 am
From: Ted Elliott <elliott....@gmail.com>
Date: Thu, 11 Feb 2010 23:06:52 -0800 (PST)
Local: Fri, Feb 12 2010 2:06 am
Subject: Re: Problem (and resolution) when using the C5 generic collection library
Thank you for finding and submitting a fix for this and a very
detailed explanation of the problem.  I will definitely add this in.
I also noticed I was using a very weak name for the type which might
have stopped all this in the first place.  I am going to switch from
typeof(ICollection<>).Name to typeof(ICollection<>).FullName.  With
just the Name property I'm basically just searching for
"ICollection`1".  Unfortunately I can't specify the assembly in there
as well.  So far this seems to be the most reliable way of testing for
a unclosed generic interface, unfortunately.

On Feb 10, 11:00 am, Bob <b...@ntlworld.com> wrote:


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
End of messages
« Back to Discussions « Newer topic     Older topic »