I am trying to get all the objects in .NET Framework with their hierarchy order with their namespaces and put them into a tree structure or some sort for academic purposes in C#. I am trying to do this for a specific .NET framework platform. Is there a way to do such thing?
Request: List everything (classes, enums, structures etc.) under System.Threading namespace
Result:
Constructors:
AbandonedMutexException
Barrier
Interlocked
blah blah
Structures:
AsyncFlowControl
CancellationToken
blah blah
Delegates:
ContexCallback
ThreadStart
blah blah
Enumerations:
blah blah
Pretty much what I want is something like this. - MSDN
Many thanks.
Edit: I am not asking for a code sample or someone to write the code for me - I just can't figure out where to start so I am looking for tips.
Here are some guidelines on how to get started:
You will need to use Reflection, i.e. the classes from the System.Reflection namespaces (Assembly, ConstructorInfo, PropertyInfo, and similar). As stated on MSDN:
The classes in the System.Reflection namespace, together with System.Type, enable you to obtain information about loaded assemblies and the types defined within them, such as classes, interfaces, and value types. You can also use reflection to create type instances at run time, and to invoke and access them.
Start by getting an instance of the Assembly class. You can either pass a type from the assembly you want to access (any type, like System.Threading.Barrier for example) and use Assembly.GetAssembly:
var assembly = Assembly.GetAssembly(typeof(System.Threading.Barrier));
Or, if you're going to iterate through a folder of .dll files, you can use use Assembly.LoadFrom:
var assembly = Assembly.LoadFrom("path-to-System.Threading.dll");
Once you have the assembly instance, you will want to iterate through the types and do further reflection upon them:
foreach (var type in assembly.GetTypes())
{
var constructors = type.GetConstructors();
var fields = type.GetFields();
var properties = type.GetProperties();
...
}
The Type class, apart from these methods, also contains various properties which allow you to see if the specified type is a class or a struct (Type.IsValueType, Type.IsInterface, Type.IsAbstract, etc.), see if one type inherits or implement a different one (Type.IsAssignableFrom(otherType), Type.GetInterfaces), and similar things.
Someone (Groo) has alread given the "theoretical" reply about how you should do it, but note that there are at least two strong caveats:
any Microsoft assembly could contain a System.Threading class (and technically any assembly could contain it, even yours, but it is bad etiquette to do it)
if you want to explore a "base" assembly (mscorlib, System, ...) from a different version of .NET than the one you are running from then you'll need Mono.Cecil or similar library, because with Reflection you can't load a different version of a base assembly than the one you are running)
And now some very simple code:
var assemblyNames = new[]
{
"mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
};
var nss = new[]
{
"System.Threading"
};
// Begin real code
var assemblies = Array.ConvertAll(assemblyNames, Assembly.Load);
var nss2 = Array.ConvertAll(nss, x => x + ".");
var types = assemblies.SelectMany(x => x.ExportedTypes).Where(x => nss2.Any(y => x.FullName.StartsWith(y))).ToArray();
// The Delegate check is taken from http://mikehadlow.blogspot.it/2010/03/how-to-tell-if-type-is-delegate.html
var classes = types.Where(x => x.IsClass && !typeof(Delegate).IsAssignableFrom(x)).ToArray();
var structs = types.Where(x => x.IsValueType && !x.IsEnum).ToArray();
var enums = types.Where(x => x.IsEnum).ToArray();
var delegates = types.Where(x => x.IsClass && typeof(Delegate).IsAssignableFrom(x)).ToArray();
// There is a DeclaringType property to see what Type is declaring them
var constructors = types.SelectMany(x => x.GetConstructors(BindingFlags.Public | BindingFlags.Instance)).ToArray();
If you can get hold of the corresponding XML file for the framework you're interested in, you might find it easier to transform that than to extract this information directly from the code.
Related
Does anybody know of an easy way to create an instance of a class given the FullName of a type (namespace.classname format), but not having the AssemblyQualifiedName? The FullName of the type is only contained in a single assembly that is referenced and available at runtime, so there is no ambiguity.
I don't have the type, I have a string - the fullname only, without the assembly part. I don't know the assembly, I just know it's referenced and there is only one assembly containing the type fullname.
Thanks!
EDIT:
This is to do with deserialization of instances from a proprietary protocol. I've recieved good answers, but what I'll end up do in order to have optimal solution and not iterate through all the assemblies is to create a static dictionary with fullName key and assembly qualified name as value, given I know which exactly are the classes and they are a limited set.
You can get all of the active assemblies and then look through each one for a type with the full name you have. You'll need to prepare for the possibility that there are multiple matches, or no matches, among the assemblies.
Load all of your assemblies and select over their types, then filter on the name.
public static object CreateType(string typeName)
{
var allTypes = AppDomain.CurrentDomain
.GetAssemblies()
.SelectMany
(
a => a.GetTypes()
);
var type = allTypes.Single( t => t.Name == typeName );
return Activator.CreateInstance(type);
}
You might consider adding some validation code to check for duplicates, and to ensure there is a default constructor.
I'm trying to understand reflection in more detail. The project I'm working on is intended to be an internal package, consumed by multiple developers. The problem, we parse a lot of data from varying departments. With documents that have varying headers, ordering, and often abbreviations of the name within the header.
Example: (Delimited Example)
Department A :
Date, Volume, Depth, Turbidity
Date and Time, Volume, Turbidity, Depth
Date, Vol., Turb., Dep.
Date, NTU, Vol, Dep ft
Department B:
Date/Time, Flow, Level, Velocity
Timestamp, Lvl, Flow, Vel.
So in the library I wanted to include a mapping file, with a method that in essence would be called GetHeaderConfigurations. Whomever references this library would be able to call the library with a user friendly name, but would pass an object with certain information.
The important piece would be their object and a namespace. Which I would recurse the namespace for classes, ones that are details about the header within the file.
The problem:
public static IEnumerable<Type> GetHeaderConfiguration(FileConfiguration configuration)
{
var assembly = Assembly.Load(configuration.HeadersNamespace);
// Some more code
}
When I call that from another application that references the library, I don't receive all of the classes. The application builds the object, then stores the namespace in the following manner "Sample.Headers.LabConfiguration". I execute the following:
var headers = Assembly.GetExecutingAssembly()
.GetTypes()
.Where(t => t.IsClass && t.Namespace == "Sample.Headers");
The above does return all the classes within the directory in the solution, but for some odd reason when I attempt to load the assembly the code fails.
I believe the issue is when I call Assembly.Load I'm passing a namespace, not an assembly. Which leads me to the root of the question I'm hoping to understand. How can I successfully use that namespace? How can I load the internal properties?
Assembly.Load() does just that, loads a new assembly (roughly speaking, a DLL or EXE). If you just want to look for classes within the current assembly, use Assembly.GetExecutingAssembly() to get the currently executing Assembly object, and then call GetTypes() on that.
var assembly = Assembly.GetCurrentlyExecutingAssembly();
var headers = assembly.GetTypes().Where(...);
MSDN has the following note regarding performance:
For performance reasons, you should call this method only when you do not know at design time what assembly is currently executing. The recommended way to retrieve an Assembly object that represents the current assembly is to use the Type.Assembly property of a type found in the assembly, as the following example illustrates.
Unless you're running this code many times in a tight loop, there's no reason to be concerned with performance in my opinion. But if you want to follow MSDN's advice, you can replace Assembly.GetExecutingAssembly() with typeof(ThisClass).Assembly where ThisClass is the name of the class containing the code. But Assembly.GetExecutingAssembly() still works (and doesn't require coupling with the class name).
Edit: I am using DataSourceProviderService.InvokeAddNewDataSource method to display Data Source Configuration Wizard during design-time in Visual Studio. If user choose an object (as explained here), and click finish, I will get a string like "Namespace.ClassName". To display the Properties of the selected object in designer, I need to find the correct Type of the object in an optimized manner.
I have the name of a class and its namespace (Application.Data.Employee). I want to find the type of the class (Employee) with this information. At present I am using the following code to find the type
string classNameWithNameSpace = "Application.Data.Employee";
Type target;
foreach(Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
foreach (Type t in assembly.GetTypes())
{
if (t.FullName.Equals(classNameWithNameSpace))
{
target = t;
break;
}
}
Note: Assembly might be present in any dll referenced in the project. My code also supports .Net Framework 2.0
I know this is not the best way because of the following reasons
1) Two or more assemblies might have same namespace name and class name
2) I saw a SO post stating, it will throw NotSupportedException for dynamic assemblies
3) On debugging found that Types in unwanted or unnecessary assemblies are checked in the loop. AppDomain.CurrentDomain.GetAssemblies() method returns 146 assemblies in a simple project during design-time debugging
4) If above code loads an unnecessary assembly into memory, it will present in memory till application domain is present (check unloading an assembly section in this link https://msdn.microsoft.com/en-us/library/mt632258.aspx)
Is there any recommended way or best approach for doing the same?
You can use these services to work with types at design-time:
ITypeResolutionServic helps you to retrieve an assembly or type by name at design time.
ITypeDiscoveryService helps you to get a list of available types at design time.
For example you can write such methods and pass them a suitable IServiceProvider which can get those service:
Type GetTypeByName(IServiceProvider provider, string typeName)
{
var svc= (ITypeResolutionService)provider.GetService(typeof(ITypeResolutionService));
return svc.GetType(typeName);
}
private List<Type> GetAllTypes(IServiceProvider provider)
{
var svc= (ITypeDiscoveryService)provider.GetService(typeof(ITypeDiscoveryService));
return svc.GetTypes(typeof(object), true).Cast<Type>().ToList();
}
I've used these mechanism in TypeConverter, UiTypeEditor, T4 templates and Add-ons. It's the same way that visual studio uses to work with types at design-time.
Here is the exact code you need to get properties:
var svc = ((DataSourceProviderService)Site.GetService(typeof(DataSourceProviderService)));
if (svc != null)
{
var result = svc.InvokeAddNewDataSource(this, FormStartPosition.CenterScreen);
if(result!=null && result.DataSources.Count>0)
{
var type = GetTypeByName(this.Site, result.DataSources[0].TypeName);
var properties = type.GetProperties().ToList();
MessageBox.Show(string.Join(",", properties.Select(x => x.Name)));
}
}
As you said that the search in your algorithm is also scanning unwanted assemblies. In case you plan to search only your own product's assemblies then you can leverage the standard nomenclature of the assemblies in case you have it. This will dramatically reduce the targeted assemblies which are scanned for the target type. Line # XYZ does the initial task of filtering the relevant assemblies assuming all the assemblies to be searched have a some standard prefix MyCompanyName.MyProductName in their name. Also I've replaced most of your calls with LINQ calls which are syntactically lot more cleaner.
string classNameWithNameSpace = "Application.Data.Employee";
Type target;
var assemblyList = AppDomain.CurrentDomain.GetAssemblies();
//line # XYZ
var filteredAssembliesOfMyProduct =
assemblyList.Where(x => x.FullName.StartsWith("MyCompanyName.MyProductName"));
foreach (Assembly assembly in filteredAssembliesOfMyProduct)
if (assembly.GetTypes().Any(x => x.FullName == classNameWithNameSpace))
{
target = assembly.GetTypes().First(x => x.FullName == classNameWithNameSpace);
break;
}
The inner loop is equivalent to calling assembly.GetType(classNameWithNameSpace), so you can skip it completely. This should take care of item 3 from your list.
Item 2 can be solved by ensuring that Assembly does not have IsDynamic flag in .NET 4.0, or checking the namespace prior to 4.0.
This code is suitable for .NET 2.0
IList<Type> matchingTypes = new List<Type>();
foreach(Assembly a in AppDomain.CurrentDomain.GetAssemblies()) {
// Skip dynamic assemblies.
if (a.GetType().StartsWith("System.Reflection.Emit.")) {
continue;
}
Type t = a.GetType(classNameWithNameSpace);
if (t != null) {
matchingTypes.Add(t);
}
}
Rewrite with LINQ and IsDynamic after .NET 4.0:
var matchingTypes = AppDomain
.CurrentDomain
.GetAssemblies()
.Where(a => !a.IsDynamic)
.Select(a => a.GetType(classNameWithNameSpace))
.Where(t => t != null)
.ToList();
The above gives you a list of all types with classNameWithNameSpace.
Dealing with item #1 is something best left to your application. You need to decide what to do with each of the types on the matchingTypes list.
It is useful to remember about type forwarding. The list above will include both types. You can use TypeForwardedToAttribute to decide which type you should actually take.
I am writing a customer class which will read CS files and spit out information based on method names and their various parameters.
This essentially reads each line looking for keys (public, class, etc) and then sees what its all about. Anyway this bit works fine, what I'm having issues with is dealing with various different Types.
So what I need to do is work out whether the type is one found natively in .Net, or something I've created, I'm really not bothered which way round just as long as I have some way of telling.
I've tried Type t = Type.GetType("My.Namespace.Classname"); but this just returns null even with the full namespace and name of my custom class object. However if I was to do the same code but with System.String it works perfectly fine, but I can't really account for each possible namespace in the entire framework. This will mean I need a way to get the type without the full namespace, or know how to check my own custom objects using GetType.
Can anybody provide any suggestions on how to go about this? Even if it was creating a new instance of the objects that would be enough, but again I don't have the full namespace for .Net objects.
Edit: Bit of a background
What I'm doing is reading classes that I've created in a StreamReader, reason being that I'm creating lots of them and need to do making between objects that one system will be able to understand, and another, so this code would read everything and just create the mapping for me. And in most cases this is perfectly fine, it is only when I have custom types, so I want to identify these are mark them.
I've tried Type t = Type.GetType("My.Namespace.Classname"); but this
just returns null
You need to provide the full assembly-qualified name:
Type t = Type.GetType("My.Namespace.Classname, MyAssembly");
From MSDN:
Parameters
typeName
Type: System.String
The assembly-qualified name of the type to get. See AssemblyQualifiedName. If the type is in the currently executing
assembly or in Mscorlib.dll, it is sufficient to supply the type name
qualified by its namespace.
Anyway, if you're looking to parse C# code an analyze it, I would take a look at NRefactory - an open source C# parser -.
Here's an introduction in CodeProject to NRefactory.
I've tried Type t = Type.GetType("My.Namespace.Classname"); but this just returns null even with the full namespace and name of my custom class object.
I suspect that's because it's not in the calling assembly or mscorlib, which are the only two assemblies checked by Type.GetType for names which aren't assembly-qualified.
If you know all the assemblies involved, you could run through each of them calling Assembly.GetType(namespaceQualifiedName) on each of them.
However, if you don't even have the namespace-qualified name, you should possibly create a lookup of all types in all the relevant assemblies, based on their names. For example:
var lookup = assemblies.SelectMany(a => a.GetTypes())
.ToLookup(t => t.Name);
At that point, for each name you have(e.g. Classname in your example) you can find all the types with that name:
foreach (var type in lookup[name])
{
// Do something with type
}
Type.GetType(some_type_name) will return type object if some_type_name is name of type declared any assemblies loaded at the moment, or in Mscorlib.dll
So if your are parsing your types from .cs files and not loading assebly - it will always be null with types names from your source file
In the web.config of my MVC project, I have this:
<appSettings>
<add key="MembershipRepository" value="Repo.MembershipRepository"/>
</appSettings>
I have a code like this:
var appSettings = ConfigurationManager.AppSettings;
string membershipRepositoryClassName = appSettings["MembershipRepository"];
Type membershipRepositoryType = Type.GetType(membershipRepositoryClassName);
IMembershipRepository repository = (IMembershipRepository)Activator.CreateInstance(membershipRepositoryType);
Suppose, the web application containing the web.config is in assembly Web.
The code segment I gave is in assembly Lib.
The class MembershipRepository is in assembly Repo.
Web has reference to both Lib and Repo.
Lib does not have reference to any other assemblies (Its liekly to be referenced as dll).
Repo may or may not have reference to Lib.
I get the membershipRepositoryType to be null. I understand that perhaps I need to specify the assembly in which MembershipRepository is. One way is to specify the assembly name in configuration (like this). But I think there should be some other ways. Otherwise how the other classes are loaded geting only the class name from the config file?
For instance, MembershipProvider class is loaded just fine from other assemblies.
How can I do the same. Or if I can't, why I can't?
From the MSDN Library documentation for Type.GetType(String):
typeName: The assembly-qualified name of the type to get. See AssemblyQualifiedName. If the type is in the currently executing assembly or in Mscorlib.dll, it is sufficient to supply the type name qualified by its namespace.
That last sentence explains why it sometimes works when you specify only the class name: If the executing code is in Repo, then you can get away with just specifying MembershipProvider. But I recommend that for clarity (and performance too), you avoid this behavior and always specify the assembly name. Alternately, if you already have a reference to the Assembly that contains your type, then you can call Assembly.GetType instead.
Nevertheless, if you truly have a scenario where you don't know which assembly contains your type, then you can search all loaded assemblies in the current AppDomain and try calling Assembly.GetType on each one:
Type type = AppDomain.CurrentDomain.GetAssemblies()
.Select(assembly => assembly.GetType(typeName))
.First(t => t != null);
What you're looking for is something like this:
var types = AppDomain.CurrentDomain.GetAssemblies().ToList()
.SelectMany( s => s.GetTypes() )
.Where( p => p.Name == membershipRepositoryClassName );
That is actually going to return a list, because a type with the same name may be declared in more than one assembly. If you are sure there is only one type, you can add .FirstOrDefault() or .Single() to the end of the chain. Use .FirstOrDefault() if you aren't sure if the type exists and want it to return null if it doesn't. Use .Single() if you are sure the type should exist is and want it to throw an exception if they type isn't found.