My project has 2 DLLs, one is Android specific and the other is platform independent. The independent DLL loads the Android assembly and calls the GetTypes method but it is not returning all of the public classes. The Android DLL has 3 classes, 2 are static with static methods only. Only one can be instantiated. The static classes are not returned.
Class1.cs (compile to dll in VS):
using System;
using System.Reflection;
namespace ClassLibrary1
{
public class Class1
{
public void test()
{
Assembly asm = Assembly.Load("ClassLibrary2");
Type T = asm.GetType("ClassLibrary2.Class2");
T.InvokeMember("Method", BindingFlags.Static | BindingFlags.InvokeMethod, null, T, null);
}
}
}
Class2.cs (Compile to a separate dll in VS):
namespace ClassLibrary2
{
public static class Class2
{
public static void Method()
{
return;
}
}
}
UnityClass.cs (Assign to a Empty GameObject in Unity 5.x):
using UnityEngine;
using System;
class UnityClass : MonoBehaviour
{
public void Start()
{
var x = new ClassLibrary1.Class1();
x.test();
}
}
Have a look at the following note in the msdn regarding BindingFlags:
You must specify Instance or Static along with Public or NonPublic or no members will be returned.
If you add BindingFlags.Public to your call you should get the member.
Also the 4th parameter target is not required when invoking a static member, you don't have to pass in the type as target, just use null.
As a last note, from personal experience i recommend to get the desired member first by using Type.GetMethod, Type.GetField, ... instead of using InvokeMember. That gives you the possibility to null check the return value to verify that you have found the member you are searching for. That is better for debugging as well as throwing meaningful exceptions during runtime.
Related
I have created a .cs files that contain the following:
namespace SetUp
{
class Config
{
public static object SetConfig(int code, bool print)
{
//My Code
}
}
}
Compiled it and added the reference to my main project called 'CSharp Side', for example. Added it to my project and everything is great. But my question is how do I access 'SetConfig()'? Because it doesn't recognize 'SetUp' or 'Config' in my code.
Simply make your class as public.
namespace SetUp
{
public class Config
{
public static object SetConfig(int code, bool print)
{
//My Code
}
}
}
You can reference code in a different assembly by fully qualifying:
SetUp.Config.SetConfig(1, true);
or include the namespace with a using directive:
using SetUp;
class SomeClass
{
void SomeMethod()
{
Config.SetConfig(1, true);
}
}
Also, both the class and the method in the referenced assembly need the public modifier. Otherwise they won't be visible outside the assembly where they are defined.
I have Created one ConsoleApplication to understand Access Specifiers.
Below is my code for internal, I can access this class from outside the Assembly.
namespace Assembly_1 //This is first assembly.
{
public class Base
{
//internal class
internal class B
{
public static void fnB()
{
Console.WriteLine("fnB");
}
}
}
}
namespace Assembly_2 //This is second assembly.
{
public class Derived : Assembly_1.Base
{
public class D
{
public void fnD()
{
B.fnB();//how can I access this class?
}
}
}
}
And this is where I am Accessing it.
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Assembly_2.Derived.D d = new Assembly_2.Derived.D();
d.fnD();
}
}
}
My Question
Right now I can Access Class B and it's methods like fnB() in Derived.
Everything works fine. but How?
How can I access the B Class outside Assembly_1?
As I worte in the comments:
You are confusing the namespace and assembly terms.
You can read about it here:(Assemblies and Namespace)
Many namespaces can be defined in a single assembly.
If you would like to check and understand the internal modifier,
then you would have to create a new class library project (that will compile into a different assembly), define the Base class there
and add a reference to it in your main console application.
Then you will see that you don't have access to it anymore and the code will not compile.
How can I access the B Class outside Assembly_1?
Because you're confusing namespaces and assemblies. An assembly is a collection of one or more namespaces, contained within a .dll or .exe file.
See also: MSDN: Assemblies in the Common Language Runtime and Understanding and Using Assemblies and Namespaces in .NET.
What you call Assembly_1 and Assembly_2 are namespaces within the same assembly.
Because internal members are visible within the same assembly, you can use Assembly_1.B from Assembly_2.D, because both namespaces reside in the same assembly.
This shows http://msdn.microsoft.com/en-us/library/bb311042.aspx that a reference to a public static extension class in a public static namespace can be skipped.
However, it doesn't work with public static variables.
using UnityEngine;
using System.Collections;
namespace NDefault
{
public static class TDefault
{
public static int CNT=71;
public static bool has_method(this object target,string method_name)
{
return target.GetType().GetMethod(method_name)!=null;
}
}
}
_
using UnityEngine;
using System.Collections;
using NDefault;
public class TController :MonoBehaviour
{
void Start ()
{
int t;
print (t.has_method("GetType")); //This prints "True"
print (CNT);//This creates error "The name `CNT' does not exist in the current context"
}
void Update ()
{
}
}
Am I right, that for using static variables and methods without a class reference, I have to inherit all classes from a non-static default class containing them, while for extension methods I should create a separate static class in a namespace? I.e. I can't store them together?
You can have extension methods and regular static methods/properties in the same static class. For clarity it is best to separate them.
When accessing static properties/methods you must specify the class they belong to. So to access the CNT static property it would be
int cnt = TDefault.CNT;
in your case it would then be
print (TDefault.CNT);
This rule applies for extension methods as well. For extension methods, you must have a using statement for the namespace the extension method is defined in. You must also specify the object that the extension method is for. In your example, your extension methods works for all classes. This usually is not advised unless you are adding value to all classes. you usually want to specify a particular class
public static class Extensions
{
public static bool NewMethod(this MyObject source)
{
return true;
{
}
The method above will only be available on the MyObject class, and not other classes. Unlike "normal" static methods, extension methods require an instance of an object in order to work as "extension methods". Both samples below will work.
MyObject o = new MyObject();
bool val = o.NewMethod();
// this also will get the value
val = Extensions.NewMethod(o);
I see this question a fair amount on SO, and I've followed that advice, but I appear to be doing something wrong. The dll seems to load in fine but the object CreateInstance is returning is null.
I have this dll:
namespace Backfill
{
public class Module : Kernel.Module
{
public override void ModuleStart()
{
//Stuff
}
}
}
In another DLL with a DIFFERENT namespace
namespace Kernel
{
public abstract class Module
{
public abstract void ModuleStart();
}
public static void KernelStart()
{
string load_dll = #"Path to DLL";
Assembly test_dll = Assembly.LoadFile(load_dll + ".dll");
Module test_mod = (Module)test_dll.CreateInstance("Kernel.Module");
test_mod.ModuleStart();
}
}
(Module)test_dll.CreateInstance("Kernel.Module"); is returning null, though. Any idea why?
(Module)test_dll.CreateInstance("Kernel.Module")
This won't work. As you specified, the Module class which you're trying to instantiate (which, I assume, is the one from the first DLL), is not in the Kernel namespace, but in the Backfill namespace. You should therefore have something along these lines:
(Module)test_dll.CreateInstance("Backfill.Module")
Kernel.Module is an abstract class. You cannot create an instance of it directly. You need to create an instance of the derived class.
Edit: Since supplying more info:
#Antonijn has the same answer. You need to specify the type that you want directly. BackFill.Module seems like the correct one.
Before Edit:
If you have the same names in multiple assemblies then yo need to use a fully qualified (including assembly name) for the type you want. For exmaple: https://stackoverflow.com/a/2300428/30225 as an possible answer.
I have a dll that I'm working with, it contains a class foo.Launch. I want to create another dll that subclasses Launch. The problem is that the class name must be identical. This is used as a plugin into another piece of software and the foo.Launch class is what it looks foe to launch the plugin.
I've tried:
namespace foo
{
public class Launch : global::foo.Launch
{
}
}
and
using otherfoo = foo;
namespace foo
{
public class Launch : otherfoo.Launch
{
}
}
I've also tried specifying an alias in the reference properties and using that alias in my code instead of global, that also didn't work.
Neither of those methods work. Is there a way I can specify the name of the dll to look in within the using statement?
You'll need to alias the original assembly and use an extern alias to reference the original assembly within the new one. Here's an example of the use of the alias.
extern alias LauncherOriginal;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace foo
{
public class Launcher : LauncherOriginal.foo.Launcher
{
...
}
}
Here's a walkthrough that explains how to implement that.
Also, you'd mentioned that you tried to use an alias before and encountered problems but you didn't say what they were, so if this won't work then please mention what went wrong.
as Chris said, you can use an alias on your original assembly.
If you can't you that, then you might be able to cheat by using a 3rd assembly
Assembly1.dll (your original)
namespace foo {
public class Launch {}
}
Assembly2.dll (dummy)
namespace othernamespace {
public abstract class Dummy: foo.Launch {}
}
Assembly3.dll (your plugin)
namespace foo{
public class Launch: othernamespace.Dummy{}
}
I'm not even proud of this!
Class name can be identical if it's defined in another namespace, but it boggles the mind why anybody would want to do that to themselves.
Maybe you need to use extern aliases.
For example:
//in file foolaunch.cs
using System;
namespace Foo
{
public class Launch
{
protected void Method1()
{
Console.WriteLine("Hello from Foo.Launch.Method1");
}
}
}
// csc /target:library /out:FooLaunch.dll foolaunch.cs
//now subclassing foo.Launch
//in file subfoolaunch.cs
namespace Foo
{
extern alias F1;
public class Launch : F1.Foo.Launch
{
public void Method3()
{
Method1();
}
}
}
// csc /target:library /r:F1=foolaunch.dll /out:SubFooLaunch.dll subfoolaunch.cs
// using
// in file program.cs
namespace ConsoleApplication
{
extern alias F2;
class Program
{
static void Main(string[] args)
{
var launch = new F2.Foo.Launch();
launch.Method3();
}
}
}
// csc /r:FooLaunch.dll /r:F2=SubFooLaunch.dll program.cs