Click to See Complete Forum and Search --> : convert *.cs file to object


dannystommen
September 4th, 2008, 06:14 AM
I want to select a .cs file and convert it into an object.

for example the file test.cs:

using System;

namespace Test{
public class TestClass {

public TestClass() {
}
}
}

Is it possible (in a completly different solution) to convert this into an object.

I want to get propertys and stuff to generate automatically an XML file.

object o; // i need to fill the object here
Type t = o.GetType();
PropertyInfo[] info = t.GetProperties();

So is it somehow possible to dynamically generate an object of TestClass (in test.cs)??

boudino
September 4th, 2008, 06:33 AM
You have to compile it to the assembly (using VS or csc.exe). Then you can reference it in you project regardless the original solution was. But you term "convert .cs file" is confusing, so I'm not sure is I understood you well.

As well, I don't understood what do you mean by "dynamically generate an object"? To instantinate it? Use new keyword. To create a class at runtime? Use reflection and emiting; look e.g. here (http://www.codeproject.com/KB/dotnet/runsharp.aspx).

dannystommen
September 4th, 2008, 08:35 AM
What I simply want to do is:
object o = new TestClass();

but the TestClass is in a file and I want to do this at runtime. For example, you select the file test.cs via an OpenDialogBox. Do I have to compile this at runtime?

Maybe an example would help me a lot.

torrud
September 4th, 2008, 09:50 AM
I believe I understood the question but why you want to do it? Is there any good reason to parse a .cs file, compile it at runtime and use the generated IL code? For me it sounds you are try to make scripting inside of a .NET application but for that there are other ways.

The easier way is to compile the .cs file and load the created assembly and use the classes as normal. Why you can not do it?

dannystommen
September 4th, 2008, 10:02 AM
Well, I use Ibatis as datamapper. And if you have a class with lots of properties en en database with lots of fields, it takes a lot time to create the SqlMaps (a xml file) Ibatis uses. They all look the same en the only thing I do then is copy/paste.

It would be much easier if it was genereted automatically. I have that part working. But at this moment I just call the method with de corresponding class (for example, I have the method CreateSqlMap(string savePath, object o) and filling in the correct parameters gives CreateSqlMap("C:\\temp\\", new TestClass() ). But now de TestClass is in my solution. I want to make an application where you can select a random .cs file, and then the SqlMap is created. So in this case, I select test.cs, and the application should 'convert' to an object of TestClass, and after that I call the method CreateSqlMap().

It should be something like this in the end
object o = ConvertCSfileToObject(file CSfile); //just made the name up
CreateSqlMap("C:\\temp\\", o );

So I need the implementation of the ConvertCSfileToObject() method

MadHatter
September 4th, 2008, 10:02 AM
as boudino stated you must compile it. from there you can reflect into the dll and do what you want to do...

C# is not a scripting or an interpreted language, so you must compile it in order to use it. once you compile and load it, you can do what you are wanting to do (through reflection though).

there are (or at least were) api's in the framework that allow you to compile a string of text, or a file, and generate an assembly on the fly, but I read somewhere that thats been depreciated.

here's an old article on it, I have no idea if it still applies: http://www.divil.co.uk/net/articles/plugins/scripting.asp

Arjay
September 4th, 2008, 02:08 PM
Well, I use Ibatis as datamapper. And if you have a class with lots of properties en en database with lots of fields, it takes a lot time to create the SqlMaps (a xml file) Ibatis uses. They all look the same en the only thing I do then is copy/paste.Why not leverage the XmlSerializer to create these xml files for you? You could create an adapter that takes the class(es) containing the properties and use reflection and XmlSerializer.Serialize method to generate the xml.

boudino
September 5th, 2008, 02:27 AM
Just for fun, I've done some investigation. You can utilize compiler in run-time like this:

string src =
@"using System;

namespace Test{
public class TestClass {

public TestClass() {}
}
}";

CodeDomProvider cdp = CodeDomProvider.CreateProvider("cs");
CompilerResults r = cdp.CompileAssemblyFromSource(
new CompilerParameters
{
GenerateExecutable = false,
IncludeDebugInformation = true,
GenerateInMemory = true
},
src);

Type t = r.CompiledAssembly.GetType("Test.TestClass");
object tInstance = Activator.CreateInstance(t);

dannystommen
September 8th, 2008, 03:03 AM
I found the same example and it works. But just for a class that doesn't use other classes. I added a custom attribute to the properties:

[DBColumn("t_ID", true)]
public int ID {
get { return _ID; }
set { _ID = value; }
}

the attribute 'DBColumn' is in another file and class (but in the same namespace)

public class DBColumn: Attribute {
private string _ColumnName;
private bool _IsKey;

....
}

So when I try to compile now I get the error:
"TestClass.cs(13,8): CS0246: The type or namespace name 'DBColumn' could not be found (are you missing a using directive or an assembly reference?)"

So I tried first to compile the class DBColumn and after that the TestClass. But still the same error. How can I fix this?

boudino
September 8th, 2008, 03:18 AM
You need to add reference to the assembly where DBColumn is defined into the CompilerParameters. Add ReferencedAssemblies = {"YourAssembly.dll"}, to the initialization block.

dannystommen
September 8th, 2008, 03:31 AM
string extAssembly = @"C:\Documents and Settings\Danny\Bureaublad\YieldManagerPlus\YieldManagerPlus.Domain\bin\Debug\YieldManagerPlus.Domain.dll";
compilerParams.ReferencedAssemblies.Add(extAssembly);

I did and it compiled.

But now when I do the next (after succesfull compilation):

Type[] types = result.CompiledAssembly.GetTypes();
if (types.Length == 1) {
Type t = types[0]; //debugger: 'name=TestClass fullname=Test.TestClass'
PropertyInfo[] properties = t.GetProperties();
foreach (PropertyInfo p in properties) {
//get my custom attribute 'DBColumn'
object[] attributes = p.GetCustomAttributes(false);
}
}

on the line p.GetCustomAttributes I get an FileNotFoundException:
Could not load file or assembly 'Test, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. Het systeem kan het opgegeven bestand niet vinden.'

The last sentence in Dutch means that the system could not find the file (like the exception already says)

dannystommen
September 8th, 2008, 09:14 AM
I forgot to copy the DLL to the directory where the executable runs. Anoher problem is solved, but a new one occurs. After I call 'object[] attributes = p.GetCustomAttributes(false);' attributes is filled with 1 object, just like I want it to. It is filled with an object of type 'Test.DBColumn'.
In the namespace where everything is compiled is called IbatisCreater. In this namespace I have an exact copy of de DBColumn class, just with a different namespace.
So when I try to do the next thing, I get an exception:
DBColumn Colomn = (DBColumn )attributes [0];//where DBColumn is type of IbatisCreater.DBColumn


InvalidCastException
Unable to cast object of type Test.DBColumn' to type 'IbatisCreater.DBColumn'.

Is it possible to cast this? The content of the 2 classes are exactly the same.

boudino
September 8th, 2008, 09:52 AM
InvalidCastException
Unable to cast object of type Test.DBColumn' to type 'IbatisCreater.DBColumn'.

Is it possible to cast this? The content of the 2 classes are exactly the same.

No, unless both class are in same hierarchy with common predecestor.

JonnyPoet
September 11th, 2008, 05:10 PM
If you have two identic classes and want to use them both and they have the same pattern why not creating an interface with that pattern and adding this interface to both classes. Maybe you may need a wrapperclass for getting this done, but afterwards this should work.

dannystommen
September 12th, 2008, 02:32 AM
I made a DLL of the class. everything works fine now