Closed silkfire closed 7 years ago
All that check is doing is making sure the property referred to by the
lambda expression is in the class being mapped. It avoids someone saying
mapper.Property(x => x.y.z, ...)
.
I've thought about support for dynamic types in the past. Time to think about it again...
On Oct 18, 2017 3:39 PM, "silkfire" notifications@github.com wrote:
I was wondering if it would be possible to add support for runtime-generated types.
The backstory is that I have an XML with a list of record structures, each record structure having its own set of fields. In my code, I'm creating instances of runtime-generated types with properties (all of type string) that have a name corresponding to the tag name in the XML.
So far so good. I've even managed to construct (albeit with much effort) the necessary Expression to supply to the Property() method (I'm using type mappers exclusively).
Unfortunately, I get an exception at this line: (https://github.com/ jehugaleahsa/FlatFiles/blob/master/src/FlatFiles/TypeMapping/ FixedLengthTypeMapper.cs#L960), because obviously, something of type object can't be assigned to my runtime type. I would guess that by perhaps removing this statement, or creating an overload method, we would be able to add support for these kind of dynamic types. I would believe that this would also add support for anonymous types as well.
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/jehugaleahsa/FlatFiles/issues/22, or mute the thread https://github.com/notifications/unsubscribe-auth/ABTgPmEzhbidkaLnACrP9NbWnqvBPag2ks5stlQJgaJpZM4P-QBW .
Thank you! You should really consider it. Would make this library pure perfection.
Okay, I assume that's why my statement isn't working, because I can't create an Expression
of type Func<(runtime type), string>
, only Func<object, string>
, and the mapping statement as:
mapper.Property(<object> => ((runtime type)<object>)).StringProperty
.
And obviously, object
can't be assigned to (runtime type)
.
Any update on whether this feature is in the works?
Interesting fact, you can't pass a lambda to a dynamic call:
dynamic foo = mapper;
foo.Property(x => x.Name);
Expression trees (which is how the type mappers work) are a compile time concept, so are not available at runtime. So even though I can generate a mapper at runtime, I can't call any methods on it to configure it. The code below generates a mapper at runtime that's more or less unusable.
public static dynamic DefineDynamic(Type type, Func<object> factory)
{
if (factory == null)
{
throw new ArgumentNullException(nameof(factory));
}
Type mapperType = typeof(SeparatedValueTypeMapper<>).MakeGenericType(type);
dynamic mapper = Activator.CreateInstance(mapperType, factory);
return mapper;
}
That all said, what you're really trying to achieve is read/write from properties of a type at runtime. What you need is a way to map columns to properties without using expression trees. I am going to spend some time tomorrow looking into a new interface that will just take property names, rather than expression trees. I already have some code started...
Side note, technically there is already partial support in FlatFiles for anonymous types... it's just a little unintuitive. Consider:
var mapper = SeparatedValueTypeMapper.Define(() => new
{
Name = (string)null
});
mapper.Property(x => x.Name).ColumnName("Name");
StringWriter writer = new StringWriter();
mapper.Write(writer, new[]
{
new { Name = "John" }, new { Name = "Sam" }
});
string result = writer.ToString();
While you can use this to write anonymous objects to a file, you could never populate anonymous objects this way, because they are read-only. FlatFiles works by first instantiating an object and then setting the properties. I couldn't tell you if anonymous types are using a giant ctor or if the backing fields are written to directly. Switching to an actual class at that point makes a lot more sense.
You should see a new NuGet package out there, version 0.3.26: https://www.nuget.org/packages/FlatFiles/
Your code should look something like this:
Type runtimeType = ...; // Assume this type has a default constructor
var mapper = SeparatedValueTypeMapper.DefineDynamic(runtimeType);
mapper.Int32Property("Id");
mapper.StringProperty("Name");
TextReader reader = ...; // Assume you are pulling data from somewhere
var records = mapper.Read(reader).ToArray(); // Read all values as IEnumerable<object>
// ... do something
TextWriter writer = ...; // Assume you are pushing data somewhere
mapper.Write(writer, records);
I can't emphasize enough that there is a lot of new code here and no where near enough unit tests to cover it all yet. That said, I do have some high-level tests and the core functionality appears to be working.
Please let me know if you encounter any odd errors; there is quite a bit of reflection going on under the hood and I know runtime-generated types don't cooperate as expected.
Thank you so much! I'm impressed that you were able and willing to implement it so quickly.
I was wondering if it would be possible to add support for runtime-generated types.
The backstory is that I have an XML with a list of record structures, each record structure having its own set of fields. In my code, I'm creating instances of runtime-generated types with properties (all of type
string
) that have a name corresponding to the tag name in the XML.So far so good. I've even managed to construct (albeit with much effort) the necessary
Expression
to supply to theProperty()
method (I'm using type mappers exclusively).Unfortunately, I get an exception at this line: (https://github.com/jehugaleahsa/FlatFiles/blob/master/src/FlatFiles/TypeMapping/FixedLengthTypeMapper.cs#L960), because obviously, something of type
object
can't be assigned to my runtime type. I would guess that by perhaps removing this statement, or creating an overload method, we would be able to add support for these kind of dynamic types. I would also think that this would have the added benefit of supporting anonymous types.