views:

1266

answers:

2

Howdie!

So I'm deserializing a class called Method using .NET Serialization. Method contains a list of objects implementing IAction. I originally used the [XmlInclude] attribute to specify all classes which implement IAction.

But now, I'd like to change my program to load all dlls in a directory and strip out the classes which implement IAction. Then users can deserialize files which contain their actions implementing IAction.

But I don't control the classes which implement IAction anymore, and so I can't use XmlInclude :( Is there a way to set this attribute at runtime? Or have a similar attribute set for the implementing class?

    public class Method
    {
        public List<Actions.IAction> Actions = new List<Actions.IAction>();
    }

    public interface IAction
    {
        void DoExecute();
    }

    public static Type[] LoadActionPlugins(string pluginDirectoryPath)
    {
        List<Type> pluginTypes = new List<Type>();

        string[] filesInDirectory = Directory.GetFiles(pluginDirectoryPath, "*.dll", SearchOption.TopDirectoryOnly);
        foreach (string pluginPath in filesInDirectory)
        {
            System.Reflection.Assembly actionPlugin = System.Reflection.Assembly.LoadFrom(pluginPath);
            Type[] assemblyTypes = actionPlugin.GetTypes();
            foreach (Type type in assemblyTypes)
            {
                Type foundInterface = type.GetInterface("IAction");
                if (foundInterface != null)
                {
                    pluginTypes.Add(type);
                }
            }
        }

        return pluginTypes.Count == 0 ? null : pluginTypes.ToArray();
    }
+4  A: 

XmlSerializer has a constructor that accepts an array of types that will be accepted when deserializing:

public XmlSerializer(
   Type type,
   Type[] extraTypes
);

You should be able to pass your array of assemblyTypes as the second argument.

David Norman
+2  A: 

You can an array of types into the Xml Serializer as David Norman has shown. One huge word of caution. Every time you do this a new xml serializer is built and compiled. If you do this a lot you will have a huge memory leak and performance hog on your hand.

This is a huge memory and performance hog, make sure you only do this once. You can resolve this by caching your xml Serializer: http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer.aspx

Snippet from MSDN:

Dynamically Generated Assemblies To increase performance, the XML serialization infrastructure dynamically generates assemblies to serialize and deserialize specified types. The infrastructure finds and reuses those assemblies. This behavior occurs only when using the following constructors:

XmlSerializer..::.XmlSerializer(Type)

XmlSerializer..::.XmlSerializer(Type, String)

If you use any of the other constructors, multiple versions of the same assembly are generated and never unloaded, which results in a memory leak and poor performance. The easiest solution is to use one of the previously mentioned two constructors. Otherwise, you must cache the assemblies in a Hashtable, as shown in the following example.

T

JoshBerke