Class library to utilize invoking namespace - c#

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).

Related

How can I get the comments for symbols referenced by a CompletionItem?

Coming from this question, I've managed to get all CompletionItem instances available for a specific offset using completionService.GetCompletionsAsync(document, offset);.
So, after querying for completions of "MyString".Len, I get a CompletionItem for the Length method and can then, using the CompletionService, call service.GetDescriptionAsync(document, completionItem) to retrieve "int string.Length { get; }".
But, how can I get the comments for Length, e.g. "Gets the number of characters in the current String object."? And, if easily possible, other information regarding potential overloads?
Assuming that you're adding references to the assemblies using
MetadataReference.CreateFromFile method, you should pass an DocumentationProvider instance as an additional parameter, like this:
MetadataReference.CreateFromFile(path, MetadataReferenceProperties.Assembly, new MyDocumentationProvider(path));
DocumentationProvider is an abstract class, we ended up implementing our own by overriding GetDocumentationForSymbol method and locating appropriate XML node inside XML document.
Looking at Roslyn source code, there is XmlDocumentationProvider class which has an abstract method GetSourceStream (where you're supposed to pass a content of .xml file that stores documentation for .NET assemblies).
Please note that for this feature to work there should be an .xml file with descriptions file next to the assembly (which is normally produced from the source code when you have compile an assembly with Documentation File option set).
For .NET assemblies these files are included as part of SDK, and normally can be found at:
C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\vxxx
We use this approach in our Roslyn-based parsers in our AlterNET Studio product. You may find a bit more information about these parsers here.
GetDescriptionAsync can only return a number of overloads, to get list of overloads available at the same position you might need to use Recommender API like this:
var model = document.GetSemanticModelAsync().Result
var symbols = Microsoft.CodeAnalysis.Recommendations.Recommender.GetRecommendedSymbolsAtPositionAsync(model, pos, workspace).Result;
This API will return a separate symbol for every overload.
We asked a while ago whether it's possible to retrieve additional information (such as underlying symbol) from CompletionItem and the short answer is no. You may refer to the discussion here:
https://github.com/dotnet/roslyn/issues/57677

Get all derived types of an abstract class within all the assemblies

I have a library that has an abstract class inside - suppose MyAbstractClass. This library is being used by some other projects (one app) within one solution.
I want to get all these classes. I created sample Program project and Program.Library that contains MyAbstractClass.
I have created two test classes derived from MyAbstractClass. One in the first project (Test1Class) and one in the second one (Test2Class).
I tried this code to find what I want:
var list = Assembly.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes())
.Where(t => t.IsClass && !t.IsAbstract && t.IsSubclassOf(typeof (MyAbstractClass)));
It worked but found only Test1Class (because - I guess - it's placed in the same assembly as the executed code presented above?). I don't know how to find all the derived classes within all the assemblies in my whole app.
I have also tried:
var list = Assembly.GetAssembly(typeof(MyAbstractClass)).GetTypes()
.Where(t => t.IsClass && !t.IsAbstract && t.IsSubclassOf(typeof (MyAbstractClass)));
But this one gives me an empty collection...
You need to be sure that all assemblies you want to look in are already loaded when you call Assembly.CurrentDomain.GetAssemblies();
An Assembly get loaded when the runtime need it (i.e. when your program reach a point in your code that "use" that assembly, or if you specifically call a Assembly.Load or Assembly.LoadFile or whatever method you can use to explicitly load it
The problem is CurrentDomain.GetAssemblies() only lists the Assemblies currently loaded in your Application Domain.
If you want to get the types in all assemblies in your application, then you need to ensure (somehow) that all assemblies are loaded.
One way of loading the assemblies manually is to use the following line of code:
var assembly = Assembly.LoadFile(#filename)
You'd need to do the above for each file, and then you can use the method CurrentDomain.GetAssemblies().

Get Type of Object from String Value

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

How to get a Type from an object in another DLL?

I've got an object called "Communication" that has a method to "CreatePdfFromTemplate". This method is going to be called from a Windows Service that has a SqlDependancy on a table that will notify when a new row is added by a method on a website.
Into my method, I pass a list of custom objects that have an "Id" and a "Name". The name, is the name of the object I need to load using reflection. For example, "Instruction". The "Id" is the Id of the object referred to in "Name" that needs to be loaded from the database. This object is not referenced or available in the runtime of my "Communication" DLL.
I'm currently falling at the first hurdle. I am trying to do the following as a first step:
// Load object information using Reflection
Type objectType = Assembly.GetExecutingAssembly().GetType(queueObject.Name);
int objectId = queueObject.Id;
I have found some info from my searches for answers that say there is a way to load a DLL by making it available in the application cache or the GAC, but I wasn't sure if this was the best way to go.
I've never used Reflection before so if you have any advice on it, or any advice on the way I have chosen to structure this in general (i.e. website adds row to DB table, SqlDependancy in Windows Service fires, calls to Communication service DLL to create PDF).
Just to give you some more information, the reason I have chosen to do it like this, is because my templates contain tags such as {Instruction.CreatedDate} where "Instruction" is the name of the object and "CreatedDate" is the name of a property, the value of which will replace the tag.
Any help on how to load this "Instruction" object in my Reflection or just on my structure in general is much appreciated. Let me know if I haven't given enough info or if what I've said isn't clear enough (this is my first StackOverflow question, although I am a long time lurker).
Thanks.
--UPDATE--
Ok, using the idea put forward from Maarten, I have managed to load my assembly and get a type from it, but I've done it slightly differently. I wasn't able to put in a specific path using the Assembly.LoadFile method, so I've done it like this:
Assembly executingAssembly = Assembly.GetExecutingAssembly();
Assembly objectAssembly = Assembly.Load(executingAssembly
.GetReferencedAssemblies()
.Where(a => a.Name == "Common")
.FirstOrDefault());
This works because the Type I am trying to get, is part of a referenced assembly in my Communication service called "Common" (which is an installed package using nuget to help keep it up to date, as it changes quite often).
Any further posts on how I'm doing this and if it's the right or wrong way would be appreciated though!
Load the assembly using Assembly.LoadFile or another overload.
Get the type using Assembly.GetType.
Use the Activator.CreateInstance once you have the type.
Cast it to dynamic, and call your method, or set your property. I'm assuming you are using .net 4.0.
var myAssembly = Assembly.LoadFile(...);
var myType = myAssembly.GetType(...);
dynamic myObject = Activator.CreateInstance(myType);
if (myObject != null) {
var createdDate = myObject.CreatedDate;
}

How to reflect over assemblies that are already loaded?

I have 2 projects in the solution. Project1UI references Project2Reports
Project1UI:
MainForm.cs
Project2Reports:
BaseReport.cs // all classes below inherit from it
Report1.cs
Report2.cs
Report3.cs
From Project1UI, how can I find all the classes that inherit from BaseReport? The project1UI already references the 2nd assembly - is there a way to do it without manually loading the 2nd assembly manually (e.g. Assembly.Load) since it's already loaded.
You have to process all the types in the assembly and look for the types that implement it.
You can use something like that (written by hand right now, it may contains errors).
foreach (Type type in Assembly.GetAssembly(typeof(BaseReport)).GetTypes())
{
if (type != typeof(BaseReport) && typeof(BaseReport).IsAssignableFrom(type))
{
// we found a type, we can store it somewhere, for example, in a list and our list in a static readonly field for fast lookup in the future.
myreports.Add(type);
}
}
You can also process all the loaded assemblies.
This however is not the best way to do that, is complicated, quite obscure and quite hard to understand.
I would use a simple factory class that will give you the instance of your report as requested, when you add a report, add it through a simple .Add call.

Categories