Assembly.GetAssembly(type) vs type.Assembly - c#

I wanted to know what are the benefits, if any, to calling either of these methods, and why?
Are they functionally equivalent, or should I always be choosing one over the other?

AFAIK they're functionally equivalent, however Assembly.GetAssembly(Type) is not available in the core-clr (Silverlight and the like)
You would get different errors based on whether or not your Type is null. Type.Assembly will throw a NullReferenceException (naturally) whereas Assembly.GetAssembly(Type) would throw an ArgumentNullException. Based on your code you might prefer one or the other.
EDIT: Looking at the source, for Assembly.GetAssembly:
public static Assembly GetAssembly(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
Contract.EndContractBlock();
Module m = type.Module;
if (m == null)
return null;
else
return m.Assembly;
}
Whereas System.Type.Assembly:
public abstract Assembly Assembly {
get;
}
If I recall correctly, the System.Type for runtime types are their own subclasses (or something like that) So I guess each one maybe overrides and simply directly returns an assembly reference. Beyond that, I don't think there's any significant difference for you to worry about with your code beyond null handling which is up to you. (Or if you're running the Core-CLR in which case you don't have Assembly.GetAssembly anyway so you must use Type.Assembly)

From the documentation for Type.Assembly
If the current Type object represents a constructed generic type, this
property returns the assembly that contains the generic type
definition.
For example, suppose you create an assembly named
MyGenerics.dll that contains the generic type definition
MyGenericStack<T>. If you create an instance of
MyGenericStack<int> in
another assembly, the Assembly property for the constructed type
returns an Assembly object that represents MyGenerics.dll
From the documentation for Assembly.GetAssembly:
In order to call this method, you must have a Type object, which means
that the assembly in which the class is defined must already be
loaded.

Related

c# generic function type not adapting to overloads

I'm writing a generic function (templated function?) in unity c# and I encountered this problem. The function was ran templated with a type deriving from Component
T component = transform.gameObject.GetComponent<T>();
if(component != null)
{
objects.Add(component);
}
I stepped through this and the value of component was "null" (which i expected) but then the program carried on and entered the if block...
In unity overloads the == / != operators to allow for null checks on their components (which are never actually null - so for example, component ??= foo should not work), but the overload of this function above should be fine when the type of T is a Component?
I eventually managed to get it working with:
if(component as Component != null){...}
But my question is, why was this necessary? Does c# not check for operator overloads of types passed into generic functions? Surely the literal type passed is swapped in at runtime?
You're right, the actual type argument is swapped in at runtime.
But the operator calls are bound statically at compile time. Operators are not instance methods of types, there are static methods defined on types. So code like this:
Component a, b;
a == b
resolves to
Component a, b;
Component.op_Equality(a, b)
at compile time1.
When you write a generic method without any constraints the compiler treats T as the most general type it can be: object. This allows you to use any methods that are defined on object, since any type substituted for T will have those methods. But it can't assume anything else, since it is entirely possible the user is going to actually supply object as the argument for T. So code like this:
Foo<T>(T a) {
if (a == null) {
// ...
}
}
has to resolve to a simple null reference check, since you can compare any object with null just by checking whether the reference equals 0 or not. It cannot resolve to
Foo<T>(T a) {
if (Component.op_Equality(a, null)) {
// ...
}
}
since at runtime you might supply object as T and pass something that is not assignable to Component to Foo. Generic methods are compiled only once for all reference types and then reused with metadata about the actual type arguments.
But you can help the compiler by saying
Foo<T>(T a) where T : Component {
...
}
Now you constrained possible values of T to subtypes of Component, so the compiler happily emits a call to the Component's equality check. If you add this constraint to your method it will solve your problem.
Judging by your use of the word "template" you might have a C++ background: the important thing to note about generics is that they are very different from C++ templates, in particular, as mentioned, they are compiled once (for reference types) so the code inside them has to work with any possible value of T. It does not recompile the code inside a generic method every time you call it (like template instantiations in C++).
=====
1 Note that the name op_Equality is not visible to the user, you can't call the method verbatim from C# code, you need to use the == operator.

Type namespace issue in C#

I have third party .Net assembly lets say ThridParty.dll which uses type "dotnet-namespace.dotnet-type from .Net assembly dotnetassembly.dll.
Now in new version of dotnetassembly.dll "dotnet-type" which was earlier in dotnet-namespace has been moved to new namespace lets say new-dotnet-namespace. Fully qualified name of dotnet-type has become new-dotnet-namespace.dotnet-type.
Now my question is, Is there any way I can tell runtime to look for type dotnet-type in new namespace i.e. new-dotnet-namespace instead of old namespace i.e. dotnet-namespace?
I know we can do use assembly redirection when we want to point new version of assembly but is it possible to redirect types within same assembly but to different namespace?
I don't have option to get new version of thridparty.dll which uses type from new namespace.
No, there is nothing in .Net Framework to redirect one type to another.
Note that namespace is just syntactic sugar to makes names shorter in source code, for .Net itself namespace is just part of the type name - so your question is essentially "can I point on type to another".
Solutions:
recompile
build proxy assembly
rewrite IL to point to new types.
How about:
public Type FindType(string typeName, string assemblyName)
{
Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().SingleOrDefault(a => a.GetName().Name == assemblyName);
return assembly != null ? assembly.GetTypes().SingleOrDefault(t => t.Name == typeName) : null;
}
You would call this:
Type dotNetType = FindType("dotnet-type", "dotnetassembly");
This way you are independent of the type namespace.
As a side note, if you have two types with the same name in that assembly, this method will simply not work because it won't be able to know which type to return (in fact, it'll throw an exception). You can change SingleOrDefault to FirstOrDefault and make it return the first occurence.
Of course you'd lose all the compiler-time advantages, since you'll be looking up the type at runtime.

Type.GetInterface returning null

My issue is that I am getting different results to our older DLLs from history, when very little has changed and I don't under how the changes are relevant to the error shown.
This is part of a method, in our SecurityPluginServices.dll module, which essentially added plugins to a list so they can be utilised by the main program.
It gets all the DLLs in a set folder, then for each it runs through the code below.
private void AddPlugin(string FileName, LoggingUtilities.Source source)
{
//Create a new assembly from the plugin file we're adding..
Assembly pluginAssembly = Assembly.LoadFrom(FileName);
try
{
//Next we'll loop through all the Types found in the assembly
foreach (Type pluginType in pluginAssembly.GetTypes())
{
if (pluginType.IsPublic) //Only look at public types
{
if (!pluginType.IsAbstract) //Only look at non-abstract types
{
//Gets a type object of the interface we need the plugins to match
Type typeInterface = pluginType.GetInterface("SecurityInterface.ISecurityPlugin", true);
//Make sure the interface we want to use actually exists
if (typeInterface != null)
{
// Do work here
}
typeInterface = null; //Mr. Clean
}
}
}
pluginAssembly = null; //more cleanup
}
catch (ReflectionTypeLoadException ex1)
{
Console.WriteLine(ex1.Message);
}
catch (Exception ex2)
{
Console.WriteLine(ex2.Message);
}
}
The issue I am having is that everytime it gets to Type typeInterface = pluginType.GetInterface("SecurityInterface.ISecurityPlugin", true); it always returns null.
The plugins I need to load are for NTLM and LDAP and they have changed very little in many versions and only a couple of extra properties and methods have been added, nothing to do with interfaces that the implement.
I've opened up a copy of the newer plugin DLL and one of the older ones in ILDASM and they both seem to contain the same information regarding the SecurityInterface.ISecurityPlugin that the .GetInterface method is seeking.
Newer LdapSecurity
Older LdapSecurity
Suggestion:
Type typeInterface = pluginType.GetInterface("SecurityInterface.ISecurityPlugin", true);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Change this to a fully-qualified type name, i.e. one that includes the assembly containing your interface type.
(If you're now saying that you've got two different types by the same name, in two different assemblies, and therefore cannot include one definite assembly name, this may well be the likely cause of your issue.)
Explanation:
My other answer led me to a suspicion of what could cause your issue. Generally speaking, typeof(T) would force you to add an assembly reference to your project for the assembly that contains T. Otherwise, compilation will fail. On the other hand, textual mentions of type names such as Type.GetType("T") do not enforce a compile-time assembly reference... but they still have to be resolved to a type instance at run-time. So if you omit the assembly name, you need to keep in mind how .NET will map T to a specific assembly.
Back to your issue. First, let's note that you are not using a fully-qualified type name:
Type typeInterface = pluginType.GetInterface("SecurityInterface.ISecurityPlugin", true);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You specify only the namespace and the type name, but not the assembly containing your interface type. Could it be that the interface type is defined more than once, i.e. in different assemblies, and your mention of that type name is resolved to type in the wrong assembly?
Let's briefly look at the MSDN documentation for Type.GetType(string) method, which describes the string parameter as follows:
"The assembly-qualified name of the type to get. […] 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."
What if the same applies to the Type.GetInterface(string, bool) method which you're using? And what if your currently executing assembly does contain a type of that name? Then that is the type that pluginType will be checked against... but it might be a different ISecurityPlugin interface type (albeit equal in name) than the one your plug-in class actually implements.
Update: Please see my other answer first, which is likely more relevant.
If you want to check whether pluginType implements the ISecurityPlugin interface, you could instead perform this check:
typeof(SecurityInterface.ISecurityPlugin).IsAssignableFrom(pluginType)
If you don't reference the assembly containing ISecurityPlugin, you can replace the first part by Type.GetType("SecurityInterface.ISecurityPlugin").

How generic methods gets instantiated in C#?

Suppose I've a generic method as:
void Fun<T>(FunArg arg) {}
Are this.Fun<Feature> and this.Fun<Category> different instantiations of the generic method?
In general, how does the generic method get instantiated? Different generic argument produces different method, or same method along with different metadata which is used at runtime?
Please support your answer with some quote(s) from the language specification.
Also, suppose I did these:
client.SomeEvent += this.Fun<Feature>; //line1
client.SomeEvent += this.Fun<Category>; //line2
client.SomeEvent += this.Fun<Result>; //line3
then later on,
client.SomeEvent -= this.Fun<Feature>; //lineX
Does the lineX undo the thing which I did at line1? Or it depends on somethig else also?
They all share a method definition, but at runtime they are different MethodInfo - because the generic type arguments define a generic method.
Supporting illustration:
Action<FunArg> a1 = Fun<X>;
Action<FunArg> a2 = Fun<Y>;
Action<FunArg> a3 = Fun<Y>;
Console.WriteLine(a1.Method == a2.Method); // false
Console.WriteLine(a3.Method == a2.Method); // true
At the JIT level, it is more complex; any reference-type parameters will share an implementation, as a reference is a reference is a reference (noting that all such T must satisfy any constraints in advance). If there are value-type T, then every combination of generic type arguments gets a separate implementation at runtime, since each requires a different final implementation.
It depends on the types involved.
For all the reference types (ie. classes), one method will be JITted to handle them all.
For all the value types (ie. structs), one method per type will be JITted.
So the information in the question is not detailed enough to answer, if Feature and Category are reference types, then yes, one method will be JITted for them. If one of them, or both, are value types, one method per value type will be JITted.
Note my use of the word JITted here. In the assembly compiled, there will be only one method, but at runtime, the JITter will create actual implementations of the generic methods according to the above rules.
Pop Quiz: What happens if you use NGEN on an assembly with generic types/methods? (hint: not what you think)
Yes, they will become two separate methods.

InvalidCastException when creating an instance using assembly.CreateInstance

I'm looking for an explanation for the following -
I have an assembly I'm loading using
Assembly assembly = Assembly.LoadFrom(filename);
I then loop on all the types in the assembly, and wish to try and find out if a type implements a particular interface and if so I want an instance of that type, I've tried several things which did not work, but when I fell back to the most basic (and probably inefficient) way, I realised there's something more fundamental I don't understand -
foreach (Type t in assembly.GetTypes())
{
foreach (Type i in t.GetInterfaces())
{
if (i.FullName == pluginInterfaceType.FullName)
{
object o = assembly.CreateInstance(t.ToString());
IInterface plugin = (IInterface)o;
That last line causes an InvalidCastException, despite the fact that the type created definitely implements that interface.
Further more - if I use Activator.CreateInstance instead of Assembly.CreateInstance (which I don't want to do), casting to the interface works just fine.
This is most probably because the interface you are casting to is not the same you find in the class.
Either because there is more the one interface with the same name, or because you loaded it more then once. For instance, because it is defined in the assembly you are dynamically loaded, and you try to cast it to the one that is statically bound.
The InvalidCastException should contain more details, like 'cannot cast x to y'.
My guess is that the assembly containing IInterface that you are loading is not exactly the same as the one your code was built against, maybe it's a local copy of a non strongly-named assembly.

Categories

Resources