views:

590

answers:

7

I have two objects and I want to merge them:

public class Foo
{
    public string Name { get; set; }
}

public class Bar
{
    public Guid Id { get; set; }
    public string Property1 { get; set; }
    public string Property2 { get; set; }
    public string Property3 { get; set; }
    public string Property4 { get; set; }
}

To create:

public class FooBar
{
    public string Name { get; set; }
    public Guid Id { get; set; }
    public string Property1 { get; set; }
    public string Property2 { get; set; }
    public string Property3 { get; set; }
    public string Property4 { get; set; }
}

I will only know the structure of Foo at runtime. Bar can be any type at runtime. I would like to have a method that will be given a type and it combine that type with Foo. For instance, the scenario above, the method was given a Bar type at runtime and I combined it with Foo.

What would be the best way to do this? Can it be done using LINQ Expressions or do I have to generate it Dynamically or is there another way? I am still learning the new LINQ namespace in C# 3.0, so excuse the ignorance if it can't be done using LINQ Expressions. This is also the first time I have ever had to do something dynamic like this with C#, so I am not quite sure of all the options I have available to me.

Thanks for any options given.

EDIT


This is strictly for adding meta information to the type given to me for serialization. This scenario keeps the user's objects ignorant of the meta information that needs to be added, before it is serialized. I have come up with two options before asking this question and I just wanted to see if there was anymore, before deciding on which one to use.

The two options I have come up with are:

Manipulating the serialized string of the type given to me after serializing it, by adding the meta information.

Wrapping the type given to me, which is similar to what @Zxpro mentioned, but mine differed slightly, which is fine. It will just make the user of my API have to follow the convention, which isn't a bad thing, since everybody is about convention over configuration:

public class Foo<T>
{
    public string Name { get; set; }
    public T Content { get; set; }
}

EDIT


Thanks everybody for their answers. I decided on wrapping the object like above and I gave the answer to @Zxpro, since a majority liked that approach also.

If anybody else comes across this question, feel free to post, if you think there might be a better way.

+2  A: 

Unfortunately, this is not something you can do easily. The best you can do is to create an anonymous type as part of a LINQ query, but that will have local scope only, and so will only be good for you in the method wherein you make it.

When .NET 4 comes out, there's a new Dynamic Runtime Library that might help you out.

Randolpho
I will definitely check out the new dynamic stuff in C# 4 when I get a chance.
Dale Ragan
+6  A: 

If you don't mind them being grouped rather than merged:

public FooEx<T>
{
    public Foo Foo { get; set; }
    public T Ex { get; set; }
}
Bryan Menard
This would be an ideal solution, but it would require compile-time knowledge of Bar, which the original asker has stated is only available at runtime.
Randolpho
@Randalpho: Maybe, maybe not. It may not be known *in that context*, but it may well be possible, depending on the architecture, to use a generic.
Adam Robinson
I've thought about that and that is my fall back plan, if this can't be done easily and performant. Mine differed slightly though. Basically making public Foo<T> { public string Name { get; set; } public T Content { get; set; } }
Dale Ragan
Not necessarily, it might be possible to use typeof(FooEx<>).MakeGenericType( ).CreateInstance( ) in certain scenarios, depending on details of what the OP needs.
Doug McClean
+1  A: 

Aside from the question "Why", the only way I can think to take two objects, one known and one unknown, and combine them into a new type would be to use Reflection.Emit to generate a new type at runtime.

There are examples on MSDN. You would have to determine weather you wanted to merge fields that had the same name or have the known type supersede the unknown type.

As far as I can tell, there is no way to do this in LINQ.

Since all you're interested in is Properties it should be pretty easy to use this article as an example. Leave out the il for creating methods and you're good to go.

Oplopanax
The "Why", is for serialization into one type for persistent storage. It would keep me from having to nest the objects, like in my comment to Zxpro.
Dale Ragan
Why not just serialize first one, then the other into the same stream/whatever?
Anton Tykhyy
@Anton Tykhyy - That is one of the options I have used. I am just looking for anything else that might be better, instead of manipulating strings, in my case.
Dale Ragan
I'd say manipulating strings is way better than any reasonable alternative if both Foo and Bar are not known completely at compile time.
Anton Tykhyy
A: 

As others have pointed out, there is no way to "merge" them (if you're thinking of a select * with multiple tables in SQL, for example). Your closest analog would be taking the route that Zxpro has provided and "group" them in a generic class.

What, exactly, would you want to accomplish with "merging" them, though? Declaring the properties explicitly would have the biggest convenience effect on writing code and compile-time safety, but if you can't specify a type then there's no opportunity for that. If you're just looking for a generic "property bag" container, then an existing data structure, such as a Dictionary<T,T> or Hashtable should be able to handle that.

Adam Robinson
+3  A: 

UNTESTED, but using the Reflection.Emit API, something like this should work:

public Type MergeTypes(params Type[] types)
{
    AppDomain domain = AppDomain.CurrentDomain;
    AssemblyBuilder builder = 
        domain.DefineDynamicAssembly(new AssemblyName("CombinedAssembly"),
        AssemblyBuilderAccess.RunAndSave);
    ModuleBuilder moduleBuilder = builder.DefineDynamicModule("DynamicModule");
    TypeBuilder typeBuilder = moduleBuilder.DefineType("CombinedType");
    foreach (var type in types)
    {
        var props = GetProperties(type);
        foreach (var prop in props)
        {
            typeBuilder.DefineField(prop.Key, prop.Value, FieldAttributes.Public);
        }
    }

    return typeBuilder.CreateType();


}

private Dictionary<string, Type> GetProperties(Type type)
{
    return type.GetProperties().ToDictionary(p => p.Name, p => p.PropertyType);
}

USAGE:

Type combinedType = MergeTypes(typeof(Foo), typeof(Bar));
BFree
Thanks for the code, I appreciate your input. I always knew Reflection.Emit was a viable solution, but I was hoping there might be other ways. I will definitely keep this in mind, if wrapping the type does not work out.
Dale Ragan
A: 

If you can add a method to the metadata class you could do something like the following

public class Foo
{
    public string Name { get; set; }
    public void SerializeWithMetadata(Bar bar)
    {
       var obj = new {
                       Name = this.Name,
                       Guid = bar.Guid,
                       Property1 = Bar.Property1
                      }
       //Serialization code goes here
    }
}

public class Bar
{
    public Guid Id { get; set; }
    public string Property1 { get; set; }
    public string Property2 { get; set; }
    public string Property3 { get; set; }
    public string Property4 { get; set; }
}

I'm not sure I would recommend this exact approach I mainly left it here to display anonymous types as a possible option that might be worth exploring

Rune FS
Problem is that neither Foo nor Bar is known prior to runtime, and your code depends on knowing that information.
Richard Hein
I fail to see how the objects type can be unknown at runtime (that would mean they are not instantiated) how ever if you ment that not all combinations of foo and bar are known at _compile time_ (or the number is too large) then the result is the same
Rune FS
"neither Foo nor Bar is known prior to runtime" ... what I meant is that you have assumed that Bar has a Guid and Property1, at compile time, and the poster asked specifically for how to merge types that are unknown at compile time.
Richard Hein
A: 

Another Option:

Modify the first class like so

public class Foo
{
    public string Name { get; set; }

    [System.Xml.Serialization.XmlAnyElementAttribute()]
    public XmlElement Any {get;set;}
}

Take the second class and serialize it into an XmlElement like so:

XmlElement SerializeToElement(Type t, object obj)
{
    XmlSerializer ser = new XmlSerializer(t);
    StringWriter sw = new StringWriter();
    using (XmlWriter writer = XmlWriter.Create(sw, settings))
        ser.Serialize(writer, obj);

    string val  = sw.ToString();

    XmlDocument doc = new XmlDocument();
    doc.LoadXml(xmlString);

    return (XmlElement)doc.DocumentElement;

}

Set property Any to the XmlElement, and serialize it You'll see the XML for the other class embedded in the document, complete with all the namespaces

You can even get away with this if the class was generated using Xsd.exe if you use the following as an element:

<xs:any namespace="##any" processContents="lax" />

I believe you can also get away with an array of XmlElements for more than one sub-class.

Deserializaing should be a matter of inspecting the XmlElements and then looking for a matching class, or perhaps using the namespace to find the class.

This is a lot tidier than messing about with string manipulation.

Oplopanax