Multi Mapping Enum at runtime - c#

Due to the question here is marked as duplicated, so here I repeat the question and make more explanation about the question. Hope someone can give some suggestions.
=======================================
As described in the question, here is a enum:
public enum MyEnum { One, Two, Three}
is going to be parsed based on mutl strings.For example, below strings are all going to be parsed as MyEnum.Two:
"Two", "TWO", "Second", "2"
The reason that I can't leverage the description attributes or a mapping dictionary directly is that the mapping strings come from an external xml file. The mapping will change after a period of time and so that It's not possible just adding the description attribute with the above declared enum.
For example, the mappings above was build one month ago and now there are some extra items required as below and these new items will be just add to the xml file:
"2nd", "The Second one"
Furthermore, I use a self developed script engine to parse above and other similar needs (that's why I don't use a simple mapping function) :
Object x = engine.Execute( /*some script codes defined in external xml*/ );
if (ReturnType.IsEnum && Enum.IsDefined(ReturnType, x)) //ReturnType is defined in external xml file
return Enum.Parse(ReturnType, x.ToString());
else if (ReturnType.IsEnum)
{
// Hope I can handle Extra mapping here
}
else
return Convert.ChangeType(x, ReturnType);
It seems very strange to just pass-in a mapping table to the above codes because it was designed for generic script executing purpose. So I think #xanatos (in the prevous 'duplicated' question) gave a way to resolve this issue, but the mapping (via customized attributes) should be generated at runtime. Attributes seems a meta data and can't be changed after compilation, however, I found some posts say that I can use TypeDescriptor to add attributes at runtime, is it possible? and How?

The fact that the data comes from an external file whose contents change, makes this an ETL/integration problem. In such cases you have to put a cleanup/normalization step before actually parsing the data.
In such cases, the typical solution is to create lookup tables that map inputs to recognized outputs and replace the input with the lookup values before parsing. In fact, ETL tools like SQL Server's Integration Services include Lookup transformations for exactly this purpose.
Once you replace your incoming data with the lookup data, you can parse it using
Enum.TryParse (String, Boolean) or
Enum.TryParse(String, Boolean, TEnum). Both methods allow you to parse the input in a case-insensitive manner and parse both values or names.

Related

How could I write to a file a dynamic object using FileHelpers?

I'm actually pursuing a way to create csv file which records could vary on type and order. They are defined by the user on both ways and I'm actually handling their types safely.
I loved using FileHelpers library in order to read/write files on C# since it's fast, reliable and trustable, so I was wondering how could I perform this export operation using it, and reviewing questions like this one the evil part comes when needing to populate the class with the desired values, so I could write the file. All the related questions are focusing on reading registries and I need to write them.
Am I right thinking that I might need to use Reflection so I could roam this new type and its properties or is there any way to "add a record" specifying the value while creating the fields?
This FileHelpers way was an option and of course the second one was doing this manually, but I was curious if there is an easier way.
var builder = new DelimitedClassBuilder("DynamicDocument", ";");
builder.AddField("Date", typeof(DateTime));
var dynamicType = builder.CreateRecordClass();
//...
Using the class builders is the best way to do this with FileHelpers. You do need to keep a copy of the type that is created so it can be used by your generic classes.
Just remember, that you must do all the work before calling CreateRecordClass() as that then generates the type.
Here is a link to another S/O question with a whole bunch of code that shows how to do it: FileHelpers.Dynamic.ClassBuilder.CreateRecordClass Error
Now, if you are working purely with properly formatted files, you can let FileHelpers do all that work for you as long as they are always properly delimited and you handle any type conversion based on the column name.

How can I extract values as strings from an xml file based on the element/property name in a generated .Net class or the original XSD?

I have a large complex XSD set.
I have C# classes generated from those XSDs using xsd.exe. Naturally, though the majority of properties in the generated classes are strings, many are decimals, DateTimes, enums or bools, just as they should be.
Now, I have some UNVALIDATED data that is structured in the correct XML format, but may well NOT be able to pass XSD validation, let alone be put into an instance of the relevant .Net object. For example, at this stage, for all we know the value for the element that should be a DateTime could be "ABC" - not even parseable as a DateTime - let alone other string elements respecting maxLength or regex pattern restrictions. This data is ready to be passed in to a rules engine that we already have to make everything valid, including defaulting things appropriately depending on other data items, etc.
I know how to use the various types in System.Xml to read the string value of a given element by name. Clearly I could just hand craft code to get out all the elements that exist today by name - but if the XSD changes, the code would need to be reworked. I'd like to be able to either directly read the XSD or use reflection on the generated classes (including attributes like [System.Xml.Serialization.XmlTypeAttribute(TypeName=...] where necessary) to find exactly how to recursively query the XML down to the the raw, unverified string version of any given element to pass through to the ruleset, and then after the rules have made something valid of it, either put it back into the strongly typed object or back into a copy of the XML for serialization into the object.
(It has occurred to me that an alternative approach would be to somehow automatically generate a 'stringly typed' version of the object - where there are not DateTimes etc; nothing but strings - and serialize the xml into that. I have even madly thought of taking the xsd.exe generated .cs file and search/replacing all the enums and base types that aren't strings to strings, but there has to be a better way.)
In other words, is there an existing generic way to pull the XElement or attribute value from some XML that would correspond to a given item in a .Net class if it were serialized, without actually serializing it?
Sorry to self-answer, and sorry for the lack of actual code in my answer, but I don't yet have the permission of my employer to share the actual code on this. Working on it, I'll update here when there is movement.
I was able to implement something I called a Tolerant XML Reader. Unlike most XML deserializing, it starts by using reflection to look at the structure of the required .Net type, and then attempts to find the relevant XElements and interpret them. Any extra elements are ignored (because they are never looked for), any elements not found are defaulted, and any elements found are further interpreted.
The main method signature, in C#, is as follows:
public static T TolerantDeserializeIntoType<T>(
XDocument doc,
out List<string> messagesList,
out bool isFromSuppliedData,
XmlSchemaSet schemas = null,
bool tolerant = true)
A typical call to it might look like this:
List<string> messagesList;
bool defaultOnly;
SomeType result = TolerantDeserializeIntoType<SomeType>(someXDocument, out messagesList, out defaultOnly);
(you may use var; I just explicitly put the type there for clarity in this example).
This will take any XDocument (so the only criteria of the original was that it was well-formed), and make an instance of the specified type (SomeType, in this example) from it.
Note that even if nothing at all in the XML is recognized, it will still not fail. The new instance will simply have all properties / public fields nulled or defaulted, the MessageList would list all the defaulting done, and the boolean out paramater would be FALSE.
The recursive method that does all the work has a similar signature, except it takes an XElement instead of an XDocument, and it does not take a schemaSet. (The present implementation also has an explicit bool to indicate a recursive call defaulting to false. This is a slightly dirty way to allow it to gather all failure messages up to the end before throwing an error if tolerant is false; in a future version I will refactor that to only expose publicly a version without that, if I even want to make the XElement version public at all):
public static T TolerantDeserializeXElementIntoType<T>(
ref XElement element,
ref List<string> messagesList,
out bool isFromSuppliedValue,
bool tolerant = true,
bool recursiveCall = false)
How it works, detail
Starting with the main call, the one with with an XDocument and optional SchemaSet:
If a schema Set that will compile is supplied (actually, it also looks for xsi:noNamespaceSchemaLocation as well) the initial XDocument and schemaSet call runs a standard XDocument.Validate() across the supplied XDocument, but this only collects any issued validation error callbacks. It won't throw an exception, and is done for only two reasons:
it will give some useful messages for the MessageList, and
it will populate the SchemaInfo of all XElements to
possibly use later in the XElement version.
(note, however, that the
schema is entirely optional. It is actually only used to resolve
some ambiguous situations where it can be unclear from the C#
object if a given XElement is mandatory or not.)
From there, the recursive XElement version is called on the root node and the supplied C# type.
I've made the code look for the style of C# objects generated by xsd.exe, though most basic structured objects using Properties and Fields would probably work even without the CustomAttributes that xsd.exe supplies, if the Xml elements are named the same as the properties and fields of the object.
The method looks for:
Arrays
Simple value types, explicitly:
String
Enum
Bool
then anything
else by using the relevant TryParse() method, found by reflection.
(note that nulls/xsi:nill='true' values also have to be specially
handled)
objects, recursively.
It also looks for a boolean 'xxxSpecified' in the object for each field or property 'xxx' that it finds, and sets it appropriately. This is how xsd.exe indicates an element being omitted from the XML in cases where null won't suffice.
That's the outline. As I said, I may be able to put actual code somewhere like GitHub in due course. Hope this is helpful to someone.

Merging Objects of different types

I have two objects (WS.Customer and EF.Customer). The reason for this is my vendor didn't expose all of the fields in their object (WS.Customer) and I need to insert and update into those fields.
I need to merge WS.Customer -> EF.Customer and later merge EF.Customer -> WS.Customer. EF.Customer will have some extra fields that WS.Customer won't have, but when the field names match - I want the values merged.
I also only want to merge values where the destination field is null, empty, or a default value in case of a Guid.
I know I could use to Linq to query each object and build the other, but is there a less verbose way of doing things? I have some other objects I need to use this approach for and don't feel like spending a weeks typing away.
Thanks
You can use one of the available object-to-object mappers library like AutoMapper or EmitMapper. They will take care of copying the data in both directions and skip fields if properly configured. For example with EmitMapper your code might look like this:
ObjectMapperManager.DefaultInstance
.GetMapper<WS.Customer, EF.Customer>(<your configuration object here>)
.Map(customerSource, customerDestination);
What do you mean by "merged"? I guess you need to "translate" from one instance to another, i.e. copy values when name and type of property matches. Please have a look at the implementation provided in ServiceStack, the extension method of object - TranslateTo method: https://github.com/ServiceStack/ServiceStack/blob/master/src/ServiceStack.Common/ReflectionExtensions.cs#L31

Building a string representation of an object using a "mask" or user supplied Format String

I'm not really sure what tags should be on this sort of question so feel free to give me some suggestions if you think some others are more suited.
I have a dynamic object with an unknown number or properties on it, it's from a sort of dynamic self describing data model that lets the user build the data model at runtime. However because all of the fields holding relevant information to the user are in dynamic properties, it's difficult to determine what should be the human readable identifier, so it's left up to the administrator. (Don't think it matters but this is an ASP.NET MVC3 Application). To help during debugging I had started decorating some classes with DebuggerDisplayAttribute to make it easier to debug. This allow me to do things like
[DebuggerDisplay(#"\{Description = {Description}}")]
public class Group
to get a better picture of what a specific instance of an object is. And this sort of setup would be perfect but I can't seem to find the implementation of this flexibility. This is especially useful on my dynamic objects because the string value of the DebuggerDisplayAttribute is resolved by the .NET framework and I have implementations of TryGetMember on my base object class to handle the dynamic aspect. But this only makes it easier for development. So I've added a field on what part of my object is still strongly typed and called it Title, and I'd like to let the administer set the implementation using their own format, so to speak. So for example they might build out a very simplistic rental tracking system to show rentals and they might specify a format string along the lines of
"{MovieTitle} (Due: {DueDate})"
I would like that when they save the record to add some logic to first update the Title property by resolving the format string to substitute each place holder with the value of the appropriate property on the dynamic object. So this might resolve to a title of
"Inception (Due: May 21, 2011)", or a more realistic scenario of a format string of
"{LastName}, {FirstName}"
I don't want the user to have to update the title of a record when they change the first name field or the last name field. I fully realize this will likely use reflection but I'm hoping some one out there can give me some pointers or even a working example to handle complex format strings that could be a mix if literal text and placeholders.
I've not had much luck looking for an implementation on the net that will do what I want since I'm not really sure what keywords would give me the most relevant search results?
You need two things:
1) A syntax for formatting strings
You have already described a syntax where variables are surrounded by bracers, and if you want to use that you need to build a parser that can parse that. Perhaps you also want to add ways to specify say a date or a number format.
2) Rules for resolving variables
If there is a single context object you can use reflection and match variable names to properties but if your object model is more complex you can add conventions for searching say a hierarchy of objects.
If you are planning to base your model objects on dynamic chances are that you will find the Clay library on CodePlex interesting.

How can I internationalize strings representing C# enum values?

I've seen many questions and answers about mapping strings to enums and vice-versa, but how can I map a series of localized strings to enums?
Should I just create an extension method like this that returns the proper string from a resource file? Is there a way to localize attributes (like "Description") that are used in solutions like this?
Which is the preferred solution - extension method or attributes. It seems to me that this isn't the intended purpose of attributes. In fact, now that I think about it, if I were to use an extension method an attribute seems like something I'd use to specify a key in a resource file for the localized string I want to use in place of the enum value.
EDIT - example:
Given the following enum,
public enum TransactionTypes {
Cheque = 1,
BankTransfer = 2,
CreditCard = 3
}
I would like a way to map each type to a localized string. I started off with an extension method for the enum that uses a switch statement and strongly typed references to the resource file.
However, an extension method for every enum doesn't seem like a great solution. I've started following this to create a custom attribute for each enumerated value. The attribute has a base name and key for the resource file containing localized strings. In the above enum, for example, I have this:
...
[EnumResourceAttribute("FinancialTransaction", "Cheque")]
Cheque = 1,
...
Where "FinanacialTransaction" is the resx file and "Cheque" is the string key. I'm trying to create a utility method to which I could pass any value from any enumeration and have it return the localized string representation of that value, assuming the custom attribute is specified. I just can't figure out how to dynamically access a resource file and a key within it.
I would definitely suggest using a resource file, probably with a method (extension or otherwise) to make it simple to get hold of the relevant resource. As the number of languages you support grows, you don't really want the code to be full of text, distracting you from the values themselves.
Likewise translation companies are likely to be geared up to handle resx files - they're not going to want to mess around in your source code, and you shouldn't let them do so anyway :)
Just use resources which are keyed on the name of the enum and the value within it. Straightforward, scales to multiple enums and multiple languages, doesn't clutter up your source code, works well with translation tools, and is basically going along with the flow of i18n within .NET.
EDIT: For mapping the enum values to the resource names, I'd just do something like:
public static string ToResourceName<T>(this T value) where T : struct
{
return typeof(T).Name + "." + value;
}
Then you could do:
string resource = MyEnum.SomeValue.ToResourceName();
Obviously that's performing string concatenation every time - you could cache that if you wanted to, but I wouldn't bother unless you had some indication that it was actually a problem.
That doesn't stop you using the extension method for non-enums, of course. If you want to do that, you need something like Unconstrained Melody.
I continued with the custom attributes and created this utility method:
public static string getEnumResourceString(Enum value)
{
System.Reflection.FieldInfo fi = value.GetType().GetField(value.ToString());
EnumResourceAttribute attr = (EnumResourceAttribute)System.Attribute.GetCustomAttribute(fi, typeof(EnumResourceAttribute));
return (string)HttpContext.GetGlobalResourceObject(attr.BaseName, attr.Key);
}

Categories