2

I'm trying to get the Class and Methods from a assembly, it works when the assembly is the same where the class is, but when it does not work when the assembly is in other project. I already add the reference from the project I want to obtain the Class and Methods but the var theList returns null. I want get the class and methods from one proyect to another , the 2 proyects are in the same solution. I need some help

class Program
{
    static void Main(string[] args)
    {

        var theList = Assembly.GetExecutingAssembly().GetTypes().ToList().Where(t => t.Namespace == "____mvc4.Models").ToList();

        Console.WriteLine("--List of Classes with his respective namescpace  : ");
        foreach (var item in theList)
        {

            Console.WriteLine(item);

        }
        Console.WriteLine("------List of classes: ");
        foreach (var item in theList)
        {

            Console.WriteLine("*****************" + item.Name + "*****************");
            MemberInfo[] memberInfo = item.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Instance);
            for (int i = 0; i < memberInfo.Length; i++)
            {
                if (!(memberInfo[i].Name.Contains("get_") || memberInfo[i].Name.Contains("set_")))
                {
                    Console.WriteLine("{0}", memberInfo[i].Name);
                }

            }

        }

        Console.ReadLine();
    }

return null

enter image description here

the asembly where are the classes that I want obtain does not appear in AppDomain.CurrentDomain.GetAssemblies().ToList();

enter image description here

Rafael Reyes
  • 2,615
  • 8
  • 34
  • 51
  • What happens if you do it without the `Where()` clause and manually look at the results? Why do you think the namespace is `____mvc4.Models`? – Philip Kendall Jan 03 '14 at 15:54
  • And is `theList` really `null`, or is it an empty list? – Philip Kendall Jan 03 '14 at 15:56
  • if I do it without the where() clause , returns the class and method from its own assembly.The var theList is empty and ____mvc4.Models is the namespace where are the classes and methods that want list @PhilipKendall – Rafael Reyes Jan 03 '14 at 16:59

4 Answers4

1

Here...

var theList = Assembly.GetExecutingAssembly().GetTypes()...etc

you are referring to the current ("executing") assembly. If you want to get types from another assembly, you need to get a reference to that assembly. A simple way to do so is to reference some type from that referenced assembly:

var otherAssembly = typeof(SomeTypeDefinedInAReferencedAssembly).Assembly;
var theList = otherAssembly.GetTypes()...etc
Heinzi
  • 167,459
  • 57
  • 363
  • 519
1

If you're trying to do this generically as possible, without knowing or caring which assemblies contain this namespaces, you need to check the loaded modules:

var theList = new List<Type>();
BuildManager.GetReferencedAssemblies();
var modules = Assembly.GetExecutingAssembly().GetLoadedModules();
theList.AddRange(modules.SelectMany(x => x.Assembly.GetTypes().Where(t => t.Namespace == "____mvc4.Models")));
Matt
  • 2,682
  • 1
  • 17
  • 24
  • The one problem I found with `GetLoadedModules` is that .NET will JIT load assemblies. So if that assembly hasn't been used yet, then it won't be in the `LoadedModules` list, which means you miss assemblies. I could be wrong, but I believe that's why I went with `AppDomain` instead. Just worth noting. I hope this comment helps. – Eli Gassert Jan 03 '14 at 16:00
  • That's a good point, and all the more reason to have that catch in your example, since there can definitely be exceptions thrown when loading an assembly for various reasons beyond permission/security errors. – Matt Jan 03 '14 at 16:02
  • still returns empty list @tencntraze – Rafael Reyes Jan 03 '14 at 17:20
  • @user1629278 Are you sure that the namespace check is correct? This code could very well have the flaws that Eli has mentioned in that they haven't been loaded yet – Matt Jan 03 '14 at 17:28
  • I'm very sure and that is why I'm so confused @tencntraze – Rafael Reyes Jan 03 '14 at 17:37
  • @user1629278 Try explicitly instantiating a variable before trying the code to ensure that the module has been loaded. Or is your problem that the module is loaded, but the `t.Namespace` part never matches? – Matt Jan 03 '14 at 17:39
  • http://stackoverflow.com/questions/2384592/c-net-is-there-a-way-to-force-all-referenced-assemblies-to-be-loaded-into-the – Eli Gassert Jan 03 '14 at 18:09
  • Edited my answer to reflect the link I posted in Eli's comments @user1629278 – Matt Jan 03 '14 at 18:28
  • I already instanciate a variable before the code and whe I tried the code with you edited answer and I get this Exception " InvalidOperationException: can not call this method during the initialization phase prior to application startup" in the line of code BuildManager.GetReferencedAssemblies(); @tencntraze – Rafael Reyes Jan 04 '14 at 17:50
1

If you want to do it dynamically, then you need to get all the assemblies in the current domain or iterate the /bin/ directory. The domain will get you all kinds of assemblies, including your standard ones, like System. /bin/ will restrict you to just your custom stuff.

Here's a utility method I use. You pass in the evaluation -- i.e. the filter -- and it spits back a list of Types.

    public static List<Type> GetClassesWhere(Func<Type, bool> evaluator)
    {
        var assemblies = AppDomain.CurrentDomain.GetAssemblies().ToList();

        var types = new List<Type>();

        foreach(var assembly in assemblies)
        {
            try
            {
                types.AddRange(assembly.GetTypes().Where(evaluator).ToList());
            }
            catch
            {
            }
        }

        return types;
    }

I try/catch each assembly individually because I found that sometimes I get some weird permission denied errors, especially in shared environments such as Azure and AppHarbor. It was always on assemblies I didn't care about anyway, so that's why I take no action on catch. For my custom assemblies, it always works for me.

In your example, you'd use it thusly (assuming you put it in a static class called Utilities)

var types = Utilities.GetClassesWhere(t => t.Namespace == "____mvc4.Models");
Eli Gassert
  • 9,745
  • 3
  • 30
  • 39
  • I try this and var types returns NULL @Eli Gassert – Rafael Reyes Jan 03 '14 at 16:46
  • That's not possible. An empty list, perhaps, but not null. You can see in my code that it always returns *something* and never null. – Eli Gassert Jan 03 '14 at 16:47
  • Switch up your query to be `t => t.Namespace.Contains('Models')` and see if you get results. – Eli Gassert Jan 03 '14 at 17:09
  • types still returns empty list @Eli Gassert – Rafael Reyes Jan 03 '14 at 17:35
  • Something seems off. I would set a breakpoint in your code and add `AppDomain.CurrentDomain.GetAssemblies()` to your watch window or immediate window and look at the assemblies it contains. Does it even contain your `____mvc4` assembly? – Eli Gassert Jan 03 '14 at 17:36
  • check my edit, you are right AppDomain.CurrentDomain.GetAssemblies() Does not it even contain my ____mvc4 assembly @ Eli Gassert – Rafael Reyes Jan 03 '14 at 17:52
  • 1
    I did a little bit of digging and both Eli's and my answers will not return an assembly unless it's been loaded. Did you try what I suggested about initializing a variable from the assembly before running this code to ensure the assembly is JIT'd? [See this answer](http://stackoverflow.com/questions/2477787/difference-between-appdomain-getassemblies-and-buildmanager-getreferencedassembl) @user1629278 – Matt Jan 03 '14 at 18:06
  • http://stackoverflow.com/questions/2384592/c-net-is-there-a-way-to-force-all-referenced-assemblies-to-be-loaded-into-the – Eli Gassert Jan 03 '14 at 18:08
-2
AppDomain.CurrentDomain.GetAssemblies()
                       .SelectMany(am => am.GetTypes())
                       .Select(a => a.Namespace == "Name of your namespace")
                       .Distinct();
Kjartan
  • 18,591
  • 15
  • 71
  • 96
Omid Rahimi
  • 457
  • 4
  • 7