3

I've got a strategy for resolving types from referenced dlls. I'm stuck on trying to resolve types that are defined in the assembly that is being compiled. I'm using the System.Reflection.Emit apis with no 3rd party libraries.

For instance:

class A {}
class B
{
    public A AnInstanceOfA {get; private set;}
}

What's the best way to resolve B's reference of A?

What about this:

class A
{
    B AnInstanceOfB {get; set;}
}
class B
{
    A AnInstanceOfA {get; set;}
}

where the classes contain instances of each other.

Is there a best practice way to do this? Any design patterns I should implement? I would prefer to use only the System.Reflection.Emit librarys but if there is a better way to do this or this can't be done with them, then using other library(s) is acceptable.

Thanks

Wesley Wiser
  • 9,491
  • 4
  • 50
  • 69
  • 3
    Type inference != resolving types in assemblies. Type inference is the task of statically deducing types of stuff that are not explicitly mentioned in the source code based on the evidences acquired from the ways they are used (as done in F#). Resolving types is just finding types based on their name. Which one do you mean? – Mehrdad Afshari Feb 09 '10 at 16:03
  • Resolving types, sorry for the confusion. – Wesley Wiser Feb 09 '10 at 17:01

1 Answers1

3

Could you elaborate on the issue that you're running into (perhaps showing code a small example of code that isn't working for you)? Because TypeBuilder derives from Type, if you're trying to define mutually recursive types you can pass the two TypeBuilders wherever you'd like to refer to the types.

EDIT

There's no need to "resolve" the types. You have access to the TypeBuilders for each and can use them just as if they were fully defined types. Here's an example that generates the code you requested in your update:

private void DefineAutoProp(string name, Type t, TypeBuilder tb)
{
    var fldName = name.Substring(0, 1).ToLower() + name.Substring(1);
    var fld = tb.DefineField(fldName, t, FieldAttributes.Private);
    var prop = tb.DefineProperty(name, PropertyAttributes.None, t, null);
    var getter = tb.DefineMethod("get_" + name, MethodAttributes.Public, t, null);
    var ilg = getter.GetILGenerator();
    ilg.Emit(OpCodes.Ldarg_0);
    ilg.Emit(OpCodes.Ldfld, fld);
    ilg.Emit(OpCodes.Ret);
    var setter = tb.DefineMethod("set_" + name, MethodAttributes.Public, typeof(void), new[] { t });
    ilg = setter.GetILGenerator();
    ilg.Emit(OpCodes.Ldarg_0);
    ilg.Emit(OpCodes.Ldarg_1);
    ilg.Emit(OpCodes.Stfld, fld);
    ilg.Emit(OpCodes.Ret);
    prop.SetGetMethod(getter);
    prop.SetSetMethod(setter);
}

public void DefineTypes()
{
    var ab = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("test"), AssemblyBuilderAccess.Run);
    var mb = ab.DefineDynamicModule("test");
    var A = mb.DefineType("A", TypeAttributes.Public | TypeAttributes.Class);
    var B = mb.DefineType("B", TypeAttributes.Public | TypeAttributes.Class);
    DefineAutoProp("AnInstanceOfA", A, B);
    DefineAutoProp("AnInstanceOfB", B, A);
    A.CreateType();
    B.CreateType();
}
kvb
  • 54,864
  • 2
  • 91
  • 133
  • @wawa - see my edit for an example of how to do what you're asking. – kvb Feb 12 '10 at 20:09
  • What if there are other methods and properties defined in A and B? Can I use the TypeBuilder in DefineAutoProp before I have finished creating all of the members of the type(s)? – Wesley Wiser Feb 15 '10 at 19:19
  • @wawa - Yes. Even in this example the property getter and setter on TypeBuilder A have not been created before it is passed into DefineAutoProp as a type. The type is only effectively frozen when CreateType is called. However, for particularly intricate mutual references it may be important to call CreateType on the TypeBuilders in a specific order (e.g. if you are defining a nested class you should call CreateType on the containing type first). – kvb Feb 15 '10 at 19:54
  • Great answer. My only issue is that you will run into problems with your automagically generated backing field if a field named "anInstanceOfA" already exists. Maybe some more steps should be taken to ensure uniqueness. – captncraig Jun 03 '10 at 16:51