简体   繁体   中英

MEF Property Always Returning Null

Original Source Code

I've got a simple business object in my BusinessObjects.dll file:

namespace BusinessObjects
{
    public class MyClass
    {
        public MyClass()
        {
            DateTime = DateTime.Now;
        }

        public DateTime DateTime { get; set; }
    }
}

In my SharedUI.dll I've got this "Context-provider" class, that I use to hold a referece to the currently selected MyClass - remember this is a simplyfied example:)...

namespace SharedUI
{
    public class AppContext
    {
        [Export]
        public MyClass SelectedMyClass { get; private set; }

        public void SetupContext(MyClass myClass)
        {
            SelectedMyClass = myClass;
        }

        public static AppContext Context
        {
            get
            {
                if (context == null)
                {
                    context = new AppContext();
                }
                return context;
            }
        }

        private static AppContext context;
    }
}

My MefTest.exe has this class:

namespace MefTest
{
    public class Program
    {
        [Import]
        public MyClass MyClass { get; set; }

        private void Compose()
        {
            var ventSystem = new MyClass();
            AppContext.Context.SetupContext(ventSystem);

            var executingAssembly = new AssemblyCatalog(Assembly.GetExecutingAssembly());
            var contextAssembly = new AssemblyCatalog(Assembly.LoadFile(string.Format(@"{0}\SharedUI.dll", Environment.CurrentDirectory)));
            var catalog = new AggregateCatalog(executingAssembly, contextAssembly);

            var container = new CompositionContainer(catalog);

            container.ComposeParts(this);
        }

        private void Run()
        {
            Compose();

            // MyClass is always null in the next line?
            Console.WriteLine(MyClass.DateTime.ToString());

            Console.ReadKey();
        }

        private static void Main(string[] args)
        {
            var p = new Program();
            p.Run();
        }
    }
}

I'm a MEF rookie so please bear with me:)

UPDATED Source Code with suggestions from Daniel Plaisted

MyClass source is the same...

SharedUI.dll now looks like this:

namespace SharedUI
{
    [Export]
    public class AppContext
    {
        [Export(typeof(MyClass))]
        public MyClass SelectedMyClass { get; private set; }

        public void SetupContext(MyClass myClass)
        {
            SelectedMyClass = myClass;
        }
    }
}

MefTest.exe now looks like this:

namespace MefTest
{
    public class Program
    {
        [Import]
        public MyClass MyClass { get; set; }

        [Import]
        public AppContext AppContext { get; set; }

        private void Compose()
        {
            var executingAssembly = new AssemblyCatalog(Assembly.GetExecutingAssembly());
            var contextAssembly = new AssemblyCatalog(Assembly.LoadFile(string.Format(@"{0}\SharedUI.dll", Environment.CurrentDirectory)));
            var catalog = new AggregateCatalog(executingAssembly, contextAssembly);

            var container = new CompositionContainer(catalog);

            container.ComposeParts(this);

            var myClass = new MyClass();
            AppContext.SetupContext(myClass);
        }

        private void Run()
        {
            Compose();

            // AppContext.SelectedMyClass is NOT null in the next line... which is good I guess :)
            Console.WriteLine(AppContext.SelectedMyClass.DateTime.ToString());

            // MyClass is always null in the next line?
            Console.WriteLine(MyClass.DateTime.ToString());

            Console.ReadKey();
        }

        private static void Main(string[] args)
        {
            var p = new Program();
            p.Run();
        }
    }
}

What am I doing wrong since I can't get it working?

When MEF needs to get an Export which is on a property of a class, it will create an instance of the class and call the property getter. So MEF is creating a new instance of your AppContext, different than the static AppContext.Context instance. The instance MEF creates doesn't have the SelectedMyClass property set on it, which is why your import ends up being null.

The problem is:

    [Import]        public MyClass MyClass { get; set; }

There are no [Export]s defined for MyClass. MEF will compose this appplication based on stuff it "knows", and since it does not know "MyClass"...

I noticed this one:

    [Export]        public MyClass SelectedMyClass { get; private set; }

This means you are trying to trick MEF into updating one of its parts from time to time? The solution to this would be to create a custom Catalog which contains "runtime" objects, in which you can updated the exported value for MyClass whenever you want. The current implementation will never resolve MyClass...

[edited:] You can decorate a member as well, but you'll have to add the class type there. So this will work:

[Export(typeof(MyClass)] public MyClass SelectedMyClass { get; private set; }

You put your Export attribute in the wrong place.

You should put it on the definition of MyClass like so:

namespace BusinessObjects
{
[Export]
public class MyClass
{
    public MyClass()
    {
        DateTime = DateTime.Now;
    }

    public DateTime DateTime { get; set; }
}
}

And then use the [Import] attribute wherever you want an instance of this class.

Remark: You cannot use MEF to move a specific instance of a class (not like this). MEF is used to create instances of a requested type and inject them at indicated places.

To learn more about MEF check out the project's page at CodePlex .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM