How to add new GENERIC type ?

Nov 8, 2010 at 2:40 AM

Hi,

thanks for the great product, I got my first task ALMOST solved. I am stuck at adding a new field to a class with a GENERIC type of an external reference.

Can anybody post some code on how to do this correctly ? Here is my scenario:

I need to add fields of type System.Data.Linq.EntityRef<T>. The assembly I am altering has NO reference to system.data.linq. I did add that reference, but adding such obviously does nothing because of one calls GetClasses there are ZERO.  I loaded the System.Data.Linq assembly directly as PE file and I see all classes (of course).

So its unclear why one needs a reference when there is nothing in the reference ? Anyway, I added the type to the reference and it than shows up.

But now I need to define the type of the generic class, so I did

PEAPI.ClassSpec _EntityType = entityRefClass.Instantiate(new PEAPI.Type[] { aField.GetFieldType() });

and than added this to my class as:

aClass.AddField(PEAPI.FieldAttr.Public, _FieldName, _EntityType);

 

The strange thing is that in ildasm and reflector all looks correct, the member shows up as something like EnitytRef<Customer>

But if I use the dll in another project it even does not compile with an error "not support in Language" if I reference the field.

If I do not reference the field, but get the fields via reflection, the field shows up but as FieldRefType and not as the other correct fields with their name.

 

I know in MSIL, references are addressed via 0x0a tokens, so I am sure somewhere I have to add the referenced type to the executing assembly so this token is created. However what about the generic implementation ? As Instantiate returns PEAPI.ClassSpec, this cannot be added via peFile.AddClass.

 

So an example would be highly appreciated....

 

Joe



Coordinator
Nov 10, 2010 at 11:56 PM
Hi Joe Not sure what is happening here. I will check it out and get back to you. I have recently done a couple of small updates to the source of PERWAPI to fix an issue in another area. The best use example of PERWAPI is as the PE-file writer for the GP Component Pascal compiler. However this does not exercise the generics at all. John
Nov 11, 2010 at 10:28 PM
Thanks for the reply.

I did another test actually ADDING the linq reference to the class and
than getting the type from that referenced assembly. Now I get even
more chaos because suddenly the class has two duplicated constructors
!

This obviously happens due to a bug with attributes, I show this at
the end of the code.

Here is the code snippets of what I did:

To my party class I added a member so the LINQ assembly and the
EntityRef now get exported:

System.Data.Linq.EntityRef<Party> _Party2 = new
System.Data.Linq.EntityRef<Party>();

In my project I loop through the referenced assemblies, when I get the
LINQ assembly I do:

ClassRef entityRefClass = _Assembly.GetClasses().Where(x =>
x.Name().StartsWith("EntityRef`1")).Single();

Than I get the Party class, and I want to add a new field owner which
should be of type EntityRef<Party> (same like the Party2 I added now
manually).

So I call: (aField is of type Party)

PEAPI.ClassSpec _EntityType = entityRefClass.Instantiate(new
PEAPI.Type[] { aField.GetFieldType() });

Inspecting this in debug time it has a GenericParameter of type party,
so I should have now a EnitytRef<Party> type.

I than add a field to my class:

aClass.AddField(PEAPI.FieldAttr.Public, "OL2S__owner", _EntityType);

Now I open the modified assembly in reflector and all seems correct:

public EntityRef<Party> OL2S__owner;

Declaring Type: OL2S.TestClassesIntercepted.Party
Assembly: TestClassesIntercepted, Version=1.0.0.0

Which is EXACTLY the same as the field (Party2) added in C# code

private EntityRef<Party> _Party2;

Declaring Type: OL2S.TestClassesIntercepted.Party
Assembly: TestClassesIntercepted, Version=1.0.0.0

Now I reference that assembly and try to use the Party class. I cannot
compile as VS.net throws me error on line:

Party _Party = new Party();

Error 3 The call is ambiguous between the following methods or
properties: 'OL2S.TestClassesIntercepted.Party.Party()' and
'OL2S.TestClassesIntercepted.Party.Party()'

Opening reflector I indeed see two ctors for Party, so perwapi somehow
added another ctor. As I mentioned above, this is a clear bug wtih
attributes. I did add the following attributes to my class (so the
fields who are just there to get the external assembly referenced to
not get modified by my code)

[Transient()]
System.Data.Linq.EntityRef<Party> _Party2 = new
System.Data.Linq.EntityRef<Party>();

[Transient()]
private System.Guid Foo;

Transient is a simple class:

public class TransientAttribute:System.Attribute
{
}

So if I DO NOT MODIFY anything, just open the assembly and write it
back , there is now a duplicated ctor ! I tracked this down to
Attributes using ILDASM, this shows me instead of a ctor:

method:$MD$18: void()

and the body for this is:

.method public hidebysig specialname rtspecialname
instance void $MD$18() cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Attribute::.ctor()
IL_0006: ret
} // end of method Party::$MD$18

Hope there is a solution for this and an example for how to add the
EntityRef class by MANUALLY adding the external assembly to the
calling one.

Thanks for any help

Joe