tags:

views:

112

answers:

4

I need to check if a certain property exists within a class. Please refer to the LINQ query in question. For the life of me I cannot make the compiler happy.

class Program
{
    static void Main(string[] args)
    {
        ModuleManager m = new ModuleManager();
        IModule module = m.FindModuleForView(typeof(HomeView));
        Console.WriteLine(module.GetType().ToString());
        Console.ReadLine();
    }
}

public class ModuleManager
{
    [ImportMany]
    public IEnumerable<Lazy<IModule>> Modules { get; set; }

    [ImportMany]
    public IEnumerable<Lazy<View>> Views { get; set; }

    public ModuleManager()
    {
        //An aggregate catalog that combines multiple catalogs
        var catalog = new AggregateCatalog();
        //Adds all the parts found in the same assembly as the Program class
        catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));
        //Create the CompositionContainer with the parts in the catalog
        _container = new CompositionContainer(catalog);
        //Fill the imports of this object
        try
        {
            this._container.ComposeParts(this);
        }
        catch (CompositionException compositionException)
        {
            Console.WriteLine(compositionException.ToString());
        }
    }

    public IModule FindModuleForView(Type view)
    {
        //THIS IS THE PROBLEM
        var module = from m in Modules
                     where (
                        from p in m.Value.GetType().GetProperties()
                        where p.GetType().Equals(view)
                        select p
                     )
                     select m;

    }
    public CompositionContainer _container { get; set; }
}

public interface IModule
{
}

[Export]
public class HomeModule : IModule
{
    public HomeModule()
    {
    }

    [Export]
    public HomeView MyHomeView
    {
        get
        {
            return new HomeView();
        }
        set
        {
        }
    }
}


public class HomeView : View
{
}

public class View
{
}
+2  A: 

GetProperties() returns an array of PropertyInfo objects. Your call to p.GetType() is always going to return typeof(PropertyInfo) - never the "view" type you've passed in.

You probably want this instead:

from p in m.Value.GetType().GetProperties() 
where p.PropertyType.Equals(view) 
select p 

Edit

As Robert pointed out, your logic to determine if the above query returns any properties is also wrong. An easy way around that is to see if anything came back from the subquery:

var module = from m in Modules 
             where ( 
                 from p in m.Value.GetType().GetProperties() 
                 where p.PropertyType.Equals(view) 
                 select p 
             ).Any()
             select m

Keep in mind that that query might return more than one module. You will probably want to return .First() from the results.

Matt Hamilton
That is right! Oops!
cmaduro
You should use .Any() ; .Count() will loop all elements in the list but Any can break when it hit the first one.
Dennis Cheung
Yeah fair enough too, @Dennis. I'll update the answer.
Matt Hamilton
+1  A: 

The where keyword expects a predicate that returns a boolean condition, but you are providing a subquery that returns an IEnumerable. Can you rework your subquery so that it returns an actual boolean condition?

You can convert it to a boolean result by using the FirstOrDefault() extension method. This method will return null if there are no records. So this should work (untested):

where ( from p in m.Value.GetType().GetProperties() 
        where p.PropertyType.Equals(view) 
        select p ).FirstOrDefault() != null
Robert Harvey
There is always only one p to satisfy it's where clause, and only one m to satisfy it's where clause. I don't know how to use the single statement in this syntax.
cmaduro
See my edit....
Robert Harvey
+1  A: 

The inner query should return bool, but returns PropertyInfo.

I haven't tested this, but I think you want something like:

    var module = (from m in Modules
                 where m.Value.GetType().GetProperties()
                    .Select(p => p.PropertyType).Contains(view)
                 select m).FirstOrDefault();

Edit:

Incorporating the Enumerable.Any suggestion on another answer:

    var module = (from m in Modules
                 where m.Value.GetType().GetProperties()
                    .Any(p => p.PropertyType.Equals(view))
                 select m).FirstOrDefault();
Jay
A: 

Even if you can get your query working, I don't think this is a good way to link your model with your view. I'd recommend creating a new question with more detail about what you are trying to do (and why), asking how you can create the association/link between the model and the view.

Daniel Plaisted
I'm not trying to hook up a model to my view. I'm trying to locate which MODULE a particular view belongs to. I don't want to decorate every single view that belongs to ModuleX, with some attribute saying [View(BelongsToModule=typeof(ModuleX))] mostly because it would be redundant. The view is already inside the class ModuleX, so why not take advantage of that?
cmaduro