I have an assembly that contains the class RD_ToBeProcessed which inherits from ToBeProcessed. The classes are in separate assemblies.
I load an object using createInstance and then attempt to cast it with the following code:
private Type tbpType = null;
public ToBeProcessed getToBeProcessedObject(string data)
{
// The data is passed in so that the fields are populated with the
// correct data.
if (tbpType==null){
Assembly assembly =
Assembly.LoadFrom("c:\\project\\RD_ToBeProcessed.dll");
tbpType = assembly.GetType("myNameSpace.RD_ToBeProcessed");
}
Object tbp = Activator.CreateInstance(tbpType,data);
// This line throws an error
return (ToBeProcessed)tbp;
}
This is a repeat of the question
.NET: Unable to cast object to interface it implements but I don't know how to resolve it.
The error thrown is
Unable to cast object of type 'myNameSpace.RD_ToBeProcessed' to type 'myNameSpace.ToBeProcessed'.
The accepted answer indicated that the problem was 2 different versions of the base assembly. But I have used ILSpy and both the ToBeProcessed dlls in the application directory and the one in the same directory as RD_ToBeProcessed report:
ToBeProcessed, Version=1.0.4336.31676, Culture=neutral, PublicKeyToken=null
So I am not sure what I am doing wrong. Should I change ToBeProcessed to be an interface (ItoBeProcessed) that is used in the app and the plugin? Then have a separate assembly that holds the base ToBeProcessed class which would not be referenced by the application at all (just the by plugin)?
EDIT: The problem was resolved by using an interface class. I still don't know what was going wrong but Kol's answer showed that in theory this should have worked correctly the way it was.
The following solution compiles and runs without error:
Assembly #1: ToBeProcessed
Compiled to DLL, which is copied to c:\project and c:\project\test. Refers to System.dll. ToBeProcessed.cs:
using System;
using System.Reflection;
[assembly: AssemblyVersion("1.0.*")]
namespace myNameSpace
{
public class ToBeProcessed
{
protected string data;
public ToBeProcessed() { }
public string Process() { return data.ToUpper(); }
}
}
Assembly #2: RD_ToBeProcessed
Compiled to DLL, which is copied to c:\project. Refers to System.dll and ToBeProcessed.dll. RD_ToBeProcessed.cs:
using System;
using System.Reflection;
[assembly: AssemblyVersion("1.0.*")]
namespace myNameSpace
{
public class RD_ToBeProcessed : ToBeProcessed
{
public RD_ToBeProcessed(string data) { this.data = data; }
}
}
Assembly #3: ToBeProcessedTest
Compiled to EXE, which is copied to c:\project\test. Refers to System.dll and ToBeProcessed.dll. ToBeProcessedTest.cs:
using System;
using System.Reflection;
[assembly: AssemblyVersion("1.0.*")]
namespace myNameSpace
{
class ToBeProcessedTest
{
private Type tbpType = null;
public ToBeProcessed getToBeProcessedObject(string data)
{
if (tbpType == null)
{
Assembly assembly = Assembly.LoadFrom("c:\\project\\RD_ToBeProcessed.dll");
tbpType = assembly.GetType("myNameSpace.RD_ToBeProcessed");
}
Object tbp = Activator.CreateInstance(tbpType, data);
return (ToBeProcessed)tbp;
}
public static void Main()
{
ToBeProcessedTest test = new ToBeProcessedTest();
ToBeProcessed tbp1 = test.getToBeProcessedObject("myData1");
Console.WriteLine(tbp1.Process());
ToBeProcessed tbp2 = test.getToBeProcessedObject("myData2");
Console.WriteLine(tbp2.Process());
Console.ReadKey(true);
}
}
}
Output:
MYDATA1
MYDATA2
some people asked it before
have look to this question in stackoverflow How to get a Static property with Reflection
check this post it explains reflection with examples. like case of inheritance and how to use type.GetMethods (BindingFlags.LookupAll) to get all methods.
Related
I have written a piece of code that loads DLL-files from disk on demand and then unloads them when a client has finished using them. The idea is that those DLLs are implementing an interface known to the client and the client can use them as plugins.
Everything seemed fine in my first tests until I created a second "plugin". The second plugin is identical with my first test case, yet I get a System.Runtime.Serialization.SerializationException. Below you see my class that I can resolve.
namespace ResolverTest.TestController1
{
using System;
...
[Serializable]
public class TestController1 : IProductController
{
public IProductConfigurationValidationResult ValidateProductConfiguration(ProductConfiguration productConfiguration)
{
var result = new ProductConfigurationValidationResult();
result.Success = true;
return result;
}
public IPerformanceCreationResult CreateProductConfigurationPerformance(ProductConfiguration productConfiguration)
{
throw new System.NotImplementedException();
}
}
}
and here is the class that it cannot resolve.
namespace ResolverTest2.TestController2
{
using System;
...
[Serializable]
public class TestController2 : IProductController
{
public IProductConfigurationValidationResult ValidateProductConfiguration(ProductConfiguration productConfiguration)
{
var result = new ProductConfigurationValidationResult();
result.Success = true;
return result;
}
public IPerformanceCreationResult CreateProductConfigurationPerformance(ProductConfiguration productConfiguration)
{
throw new System.NotImplementedException();
}
}
}
The exact exception I get says:
Unhandled Exception: System.Runtime.Serialization.SerializationException: Type i
s not resolved for member 'ResolverTest2.TestController2.TestController2,Resolve
rTest2.TestController2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
Note that both classes are public, so there is no problem accessing them. My class that handles the loading of the DLLs into an appdomain inherits MarshalByRefObject so that part is also properly defined. It seems like there is something different between TestController1 and TestController2. The .net versions are the same and I even checked the assembly info. They do not have different dependencies than each other and the reference list is exactly the same for both of them. Last but not least, the class that resolves the DLLs is checking that the path passed is correct, otherwise it throws and exception.
What else should I look at?
I am having a DLL file. With the use of DLL, I have to call the methods and add some more methods in my project. Now, I need to migrate the older DLL to Make that project as a new DLL. I done this But the problem is The C# code is converted to net module it shows two errors. I am not clear about that. kindly help me over it.
DLL Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace mcMath
{
public class mcMathComp
{
private bool bTest = false;
public mcMathComp()
{
// TODO: Add constructor logic here
}
/// <summary>
/// //This is a test method
/// </summary>
public void mcTestMethod()
{ }
public long Add(long val1, long val2)
{
return val1 - val2;
}
/// <summary>
/// //This is a test property
/// </summary>
public bool Extra
{
get
{
return bTest;
}
set
{
bTest = Extra;
}
}
}
}
CS Project:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using mcMath;
namespace mcClient
{
class Program
{
static void Main(string[] args)
{
mcMathComp cls = new mcMathComp();
long lRes = cls.Add(23, 40);
cls.Extra = false;
Console.WriteLine(lRes.ToString());
Console.ReadKey();
}
}
}
Errors:
Program.cs(5,7): error CS0246: The type or namespace name 'mcMath' could >not be found (are you missing a using directive or an assembly reference?)
Tried Methods:
I will add the reference via Project-> Add Reference.
The using Reference also used.
Put the DLL into the current project debug/release folder
I'm guessing you used to have the code side by side, i.e.
public int Add(int a, int b)
{
return a + b;
}
public void SomeMethod()
{
var result = Add(2,3);
}
This works because the scope (this.) is applied implicitly, and takes you to the Add method on the current instance. However, if you move the method out, the scope is no longer implicit.
You will need one of:
the type name if it is a static method
or a static using if using C# 6
a reference to the instance if it is an instance method
Then you would use one of (respectively):
var result = YourType.Add(2,3); (plus using YourNamespace; at the top)
using static YourNamespace.YourType; at the top
var result = someObj.Add(2,3);
Checking the compiler message, it sounds like you've done something like (line 7):
using YourNamespace.YourType.Add;
which is simply wrong; you don't use using to bring methods into scope - only namespaces and (in C# 6) types.
Likewise, I suspect you have (line 22):
var result = YourNamespace.YourType.Add(x,y);
which is not valid as this is not a static method.
Create and Using DLL in same Project in c#
DLL or Class Library is a separate project that can be part of same solution.
As you already know, adding a reference to that dll/project will make it available in your app project.
However if function Add in dll is in different namespace (which would be normal) u would need to add using clause at the beginning of your class
I suspect this is a question which has been asked many times before but i haven't found one.
I normally use fully qualified namespaces if i don't use that type often in the file or i add using namaspacename at the top of the file to be able to write new ClassName().
But what if only a part of the full namespace was added ? Why can't the compiler find the type and throws an error?
Consider following class in a nested namespace:
namespace ns_1
{
namespace ns_1_1
{
public class Foo { }
}
}
So if i now want to initialize an instance of this class, it works in following ways:
using ns_1.ns_1_1;
public class Program
{
public Program()
{
// works, fully qualified namespace:
var foo = new ns_1.ns_1_1.Foo();
// works, because of using ns_1.ns_1_1:
foo = new Foo();
}
}
But following doesn't work:
using ns_1;
public class Program
{
public Program()
{
// doesn't work even if using ns_1 was added
var no_foo = new ns_1_1.Foo();
}
}
it throws the compiler error:
The type or namespace name 'ns_1_1' could not be found (are you
missing a using directive or an assembly reference?)
I assume because ns_1_1 is treated like a class which contains another class Foo instead of a namespace, is this correct?
I haven't found the language specification, where is this documented? Why is the compiler not smart enough to check if there's a class or namespace(-part)?
Here's another - less abstract - example of what i mean:
using System.Data;
public class Program
{
public Program()
{
using (var con = new SqlClient.SqlConnection("...")) // doesn't work
{
//...
}
}
}
Edit: now i know why this seems very strange to me. It works without a problem in VB.NET:
Imports System.Data
Public Class Program
Public Sub New()
Using con = New SqlClient.SqlConnection("...") ' no problem
End Using
End Sub
End Class
This obvious way unfortunately not working but you can make all this by an alias namespace:
using ns_1_1 = ns_1.ns_1_1;
public class Program
{
public Program()
{
var no_foo = new ns_1_1.Foo();
}
}
The documentation says:
Create a using directive to use the types in a namespace without having to specify the namespace. A using directive does not give you access to any namespaces that are nested in the namespace you specify.
So the using only includes the types (not the namespaces) that are defined in the specified namespace. In order to access types of nested namespace you need to specify it explicitly with a using directive as you did in your first example.
This is documented in the standard in 3.8 Namespace and Type Names, but it's a bit convoluted to follow.
The gist of it that a partial namespace reference is only looked for in the namespace where it occurs, and each layer outwards. using-directives are not checked.
In your example, ns_1_1.Foo would be found if Foo is found anywhere in:
Program.Program.ns_1_1.Foo
Program.ns_1_1.Foo
ns_1_1.Foo
Partial namespaces will work only if your current class is part of that partial namespace. Using statements are not considered for accessing types through partial namespace.
For instance this will work because your current namespace is ns_1
namespace ns_1
{
public class Program
{
public Program()
{
var no_foo = new ns_1_1.Foo();
}
}
}
I used this code in c++ to use a class (that I defined before)in my other Apps.
#include class_name ;
How can I define a public class that could be used in all apps?
Thanks
To access classes from external assemblies you must add a reference to an external assembly. This will allow you to access public classes from the external assembly.
To specify a class from a namespace outside your current scope you must prefix the class's type specifier with its namespace name. To avoid this overhead, you can "include" the external namespace with the using directive.
Multiple namespaces can exist within a single assembly.
Assembly Fruit:
namespace Common
{
public class Strange
{
var mystery = new Mystery() // Won't compile, no reference to Mystery.
}
}
namespace Fruit
{
public class Orange
{
}
}
Assembly Vegetables:
References Fruit
namespace Common
{
public class Mystery
{
}
}
namespace Fungi
{
public class Mushroom
{
}
}
namespace Vegetables
{
using Common;
public Class Carrot
{
var strange = new Strange() // Compiles correctly.
var mystery = new Mystery() // Compiles correctly.
var orange = new Orange() // Won't compile, what's an Orange?
var orange = new Fruit.Orange() // Compiles correctly.
var mushroom = new Mushroom() // Won't compile, what's a Mushroom?
var mushroom = new Fungi.Mushroom() // Compiles correctly.
}
}
You need to create a Class Library project, which compiles to a DLL file.
You can then add a reference to it in other projects.
You have to include the namespace as below and also add any references if in another project.
using class_namespace;
If the other class is public or internal (and in the same assembly if they are internal), is in the same project, and has the same namespace, then you don't need to do anything at all. You will be able to refer to the other class by just using it's class name.
If they are in different namespaces then you can use a using statement (at the top of the file) to bring the other namespace into scope, or you can refer to the other class using the fully qualified name (i.e. OuterNamespace.InnerNamespace.ClassName) every time you use the class. (Which almost nobody ever does, everyone just uses using statements because they are so much more convenient.)
If the class is in another project entirely then you will need to add a reference to that class through visual studio. If you are creating a project that is designed to be referenced by other projects then it's project type should be a "class library".
Every class is created under a namespace
namespace abc{
public MyClass{
//functionality
}
}
To use your class on a different application,you need to import the namespace.
using abc;
public class usingClass{
MyClass obj = new MyClass();
}
I created a Console application which searches for plugins ending with PlugIn.dll.
It loads the dll assembly and executes the write method of plugInClass in PlugIn.dll.
I created an interface called IWrite which includes the write method.
After executing the console app,it gives an error as given below:
Unable to cast object of type 'HPlugIn.plugInClass' to type 'ConsolePlugIn.IWrite'.
Here is my code for console app..[Main application]
using System;
using System.IO;
using System.Reflection;
namespace ConsolePlugIn
{
interface IWrite
{
void write();
}
class Program
{
static void Main(string[] args)
{
foreach (string s in Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "*PlugIn.dll"))//getting plugins in base directory
{
Assembly aWrite = Assembly.LoadFrom(s);
Type tWrite = aWrite.GetType("HPlugIn.plugInClass");
IWrite click = (IWrite)Activator.CreateInstance(tWrite);//giving casting error
click.write();
}
}
}
}
here is my code for the plugIn dll file
using System;
namespace HPlugIn
{
interface IWrite
{
void write();
}
public class plugInClass : IWrite
{
public void write()
{
Console.Write("High from plugInClass");
}
}
}
Any idea for this casting error?
Thanks in advance!
The IWrite interfaces in the EXE and in the DLL are not the same, even though their structures are identical. You need to make a third dll with the interface, and share it among the DLLs and the EXE.
Common:
namespace Shared {
interface IWrite {
void write();
}
}
DLL:
using System;
using Shared;
namespace HPlugIn {
public class plugInClass : IWrite {
public void write() {
Console.Write("High from plugInClass");
}
}
}
EXE:
using System;
using System.IO;
using System.Reflection;
using Shared;
namespace ConsolePlugIn {
class Program {
...
}
}
You have defined the IWrite interface twice in 2 different assemblies. They are considered different types and you cannot cast from one to the other. The best way to achieve weaker coupling between the EXE and the assembly is to define this interface into a separate DLL. Then have the plugin and executable both reference this third assembly containing the contract (the IWrite interface).
There are two different IWrite interfaces. One in the console app and one in the dll. There are two ways to work around this.
Make the dll reference the console app and have plugInClass implement the ConsolePlugIn.IWrite interface.
Use the dynamic keyword to make interfaces looking the same match.