Skip to content

Anonymous Type to interface convertion

Alexei Stryker edited this page Jun 27, 2018 · 7 revisions

In some special cases (e.g. unit tests) it may be required to convert an anonymous type to a type that implements a certain interface. The CreateType(object) extension (Cauldron.Interception Fody addins) offers this functionality.
This also can be handy in situations where it is an overkill to create a new class.
Lazy programmers will love this. To achieve this, a new type is weaved into your assembly.

Example 1

    private static void Main(string[] args)
    {
        var sample = new { Index = 0, Name = "Hello" }.CreateType<ISampleInterface>();
        Console.WriteLine(sample.Name);
    }

What gets compiled:

    private static void Main(string[] args)
    {
        var sample = Assign(new
        {
            Index = 0,
            Name = "Hello"
        });
        Console.WriteLine(sample.Name);
    }
    
    [EditorBrowsable(EditorBrowsableState.Never)]
    private static SampleInterfaceCauldronAnonymousType Assign(AnonymousType<int, string> anonymousType)
    {
        return new SampleInterfaceCauldronAnonymousType
        {
            Index = anonymousType.Index,
            Name = anonymousType.Name
        };
    }

The created type:

[EditorBrowsable(EditorBrowsableState.Never)]
[Serializable]
public sealed class SampleInterfaceCauldronAnonymousType : ISampleInterface
{
	public int Index { get; set; }
	public string Name { get; set; }
}

Example 2

public IAddressData GetAddress(IUser user)
{
   var data = Factory.Create<IDatabase>().GetAddress(user.UserId);
   return new {
       UserId = user.UserId,
       Country = GetCountryName(data.CountryCode),
       Street = $"{data.Street} {data.StreetNumber}",
       ZipCode = data.ZipCode.ToString(),
       Name = user.Fullname
   }.CreateObject<IAddressData>();
}

The weaver will create a new public type that implements IAddressData and it will also add a new method to your class that assigns the value of the anonymous type to the public type.

private GeneratedTypeThatImplementsIAddressData Assign(TheAnonymousType anon)
{
    return new GeneratedTypeThatImplementsIAddressData
    {
        UserId = anon.UserId,
        Country = anon.Country,
        Street = anon.Street,
        ZipCode = anon.ZipCode,
        Name = anon.Name
    };
}

Your original implementation will be modified like the following:

public IAddressData GetAddress(IUser user)
{
   var data = Factory.Create<IDatabase>().GetAddress(user.UserId);
   return Assign(new {
       UserId = user.UserId,
       Country = GetCountryName(data.CountryCode),
       Street = $"{data.Street} {data.StreetNumber}",
       ZipCode = data.ZipCode.ToString(),
       Name = user.Fullname
   });
}