FileHelpers: mixing Delimited and Fixed Length Records - c#

Here I have to write out a file which records are Pipe Separated, using FileHelpers and C#. Great part of fields have variable length (so, my records would be [DelimitedRecord("|")] ). But some fields must have fixed length (they must have paddings, specific format and so on).
I've googled a bunch with no goal on how to accomplish that.
Example:
[DelimitedRecord("|")]
public class Customer
{
public int CustId; //variable length
public string Name; //variable length
public decimal Balance; //variable length
[FieldConverter(ConverterKind.Date, "dd-MM-yyyy")]
public DateTime AddedDate;
public int Code; // this one must have 10 characters with "zero-fill", like
// 153 must look like 0000000153
}
How do I accomplish that? Do I have to use a Converter approach and write my own converter for this?
Thank you in advance.

For anyone who comes across this question in the future, here is some working code to solve this problem.
This class is a converter which the FileHelper engine will use to convert the integer to a string, padded with 0s up to the size specified in the constructor.
public class PaddedIntConverter:ConverterBase
{
private int _size;
public PaddedIntConverter(int size)
{
_size = size;
}
public override object StringToField(string from)
{
return int.Parse(from);
}
public override string FieldToString(object from)
{
return from.ToString().PadLeft(_size,'0');
}
}
The converter can then be applied to your class like this:
[FixedLengthRecord(FixedMode.ExactLength)]
public class MyClass{
[FieldFixedLength(7)]
[FieldConverter(typeof(PaddedIntConverter), 7)]
public int RecordCount;
}

FileHelpers has an attribute [FieldFixedLength(xxx)], I believe this should get you what you are looking for (http://filehelpers.sourceforge.net/attributes.html).

As mentioned by #TYY, I wrote my own "multiuse" converter, just like this:
public StringNumberCharConverter(
string Size,
string PaddingChar,
string PaddingType,
string RemoveSpecialChars)
{
//implementation here
}
Since FileHelpers converters accept string args only, I had to parse everything on proper objects inside the Converter constructor.
For the parameters, I've converted "Size" to an "integer", PaddingChar onto a "char", PaddingType onto a custom padding type enum (i.e: Padding.LEFT or Padding.RIGHT, so if a "left" is comming from parameters, I should use String.PadLeft() and so on), and the "RemoveSpecialChars" parameter were converted onto a boolean (flag to check if the converter should remove special characters or not.)
Since I need Object-to-File conversion, all the conversion logic is inside "FieldToString" method implementation of ConverterBase abstract method.

Related

Is there a way to use a conditional when declaring method variables?

Maybe I am missing the correct language to describe this, but I am trying to utilize a pre-existing method with a different BO than currently passed.
I guess it would be something like:
public override SetInsurance(BusinessObjects.Utilities.LandViewer Viewer_land || BusinessObjects.Utilities.SeaViewer Viewer_sea, DataTable patient, int InsurancePriority)
{
}
Any help is appreciated as this might just not exist.
*//Note that these BOs are 95 percent similar but combining them is not an option in our codebase.
You should take the bits that are 95% similar (or at least the bits you'd like to use in this and other methods that can work with either type), and put them in an interface, say interface IViewer. Have both LandViewer and SeaViewer implement that interface, and have the method take it, eg:
interface IViewer {
string Name {get;set;}
}
class LandViewer: IViewer {
public string Name {get;set;}
public int SomeValue;
}
class SeaViewer: IViewer {
public string Name {get;set;}
public string SomeOtherValue;
}
public override SetInsurance(IViewer viewer, DataTable patient, int InsurancePriority) {
Console.WriteLine(viewer.Name); //.Name is accessible as it's part of the 95%
// .SomeValue and .SomeOtherValue are not accessible, because they're not part of the 95%
}

How to convert between FixedLength and Delimited records?

I'm trying to read a fixed length file and convert it to a delimited file format for use in Excel. Using the FileHelpers library I'm able to read/write either of these formats, but I'm having trouble converting between them.
My closest approach is to declare an abstract class for the record where I declare the fields in, specify the order and use any Converters. Then from that abstract class, derive a class for the delimited record and the fixed length record. I manage to get this to work up until I try to create the fixed length engine, at which point I get an exception that apparently some of the attributes aren't taking.
Here's what I have so far:
void Main()
{
// Arrange
var delimitedEngine = new FileHelperEngine<CustomerDelimitedRecord>();
var fixedLengthEngine = new FileHelperEngine<CustomerFixedLengthRecord>();
var input = #"C:\input.csv";
var output = #"C:\output.csv";
// Act
var records = (CustomerRecord[]) delimitedEngine.ReadFile(input);
fixedLengthEngine.WriteFile(output, (CustomerFixedLengthRecord[])records);
}
// Define other methods and classes here
public abstract class CustomerRecord
{
[FieldOrder(2)]
public string Name;
[FieldOrder(1)]
public int ID;
}
[DelimitedRecord(",")]
public class CustomerDelimitedRecord : CustomerRecord
{
}
[FixedLengthRecord]
public class CustomerFixedLengthRecord : CustomerRecord
{
[FieldFixedLength(50)]
public new string Name;
[FieldFixedLength(5)]
public new int ID;
}
This seems to not have any errors, but I get the following runtime exception:
Bad Usage Exception
The field: 'Name' must be marked the FieldFixedLength attribute
because the record class is marked with FixedLengthRecord.
I'm not sure if I'm on the right track, but I'm open to any suggestions. I feel this still wouldn't be the best solution, since I have to write the fields twice for the fixed length record class, but at least I don't have to write some of the attributes twice and save myself some mapping code.
By the way, I should be using at least autoproperties, but the limitations of FileHelpers means I can't because I need to use Custom Converters.

Why do i get different decimal points?

I created a structure which contains several fields.
In that structure I have a property which calls a method which then creates a string out of those number for logging purposes.
When I use the property in the structure I get different decimal points Vs when I directly call the actual method which creates the log-string!
Suppose I have 9990M, if I use the structure it is 9990.0000 and when I call the method directly it prints 9990.00
This is my Method :
private static string CreateLog(
long userId, decimal amount,
long transactionID, decimal totalCash)
{
Values = string.Format("{0}{1}{2}{3}",
amount,
userId,
transactionId,
totalCash);
return Values;
}
And my structure looks like this:
public struct AccountStruct
{
public long USER_ID;
public decimal AMOUNT;
public long TRANSACTION_ID;
public decimal CURRENT_CASH;
string ValuesToBeLoged
{
get
{
return CreateLog(this);
}
}
}
And CreateLog looks like this (calls the former method)
private static string CreateLog(AccountStruct accinfo)
{
return CreateLog( accinfo.USER_ID,
accinfo.AMOUNT,
accinfo.TRANSACTION_ID,
accinfo.CURRENT_CASH);
}
Why is it like this ? whats the problem here?
Probably some sort of internal normalization is going on. If you care about such matters, you need to specify how many decimal places you want in the ToString or String.Format method.
Look up Decimal.ToString(String) for your options. Usually I use the "Nx" where x is the number of decimal places.

C# Return Value, But keep getting error. Why?

Hello fellow stackoverflow members!
I'm very new to the C# language transfer from Java, Obj-C.
It looks pretty same as Java, but I have trouble issue in very simple thing.
I have created two individual class files, Class-A and Class-Human.
Specification for Class-A
it contains the static main method declared.And I've tried to create the new instance of Class-Human.
public static void main(String args[])
{
Human human = new Human("Yoon Lee", 99);
int expected = human.getNetID; //<-gets the error at this moment.
}
Specification for Class-Human
namespace Class-A
{
public class Human
{
public String name;
public int netId;
public Human(String name, int netId)
{
this.name = name;
this.netId = netId;
}
public int getNetID()
{
return netId;
}
}
Why can't copy over into local variable?
The compiler prompts me the error of
'Cannot convert method group of 'getNetID' delegate blah blah'
Thank you.
Change the method-call to:
int expected = human.getNetID();
In C#, method-calls require parantheses () containing a comma-separated list of arguments. In this case, the getNetID method is parameterless; but the empty parantheses are still required to indicate that your intention is to invoke the method (as opposed to, for example, converting the method-group to a delegate-type).
Additionally, as others have pointed out, there is a mismatch betweem the return-type of the method and the variable you're assigning its value to, which you're going to have to resolve somehow (change both the field-type and method return-type to int / parse the string as an integer, etc.).
On another note, C# natively supports properties for getter-setter semantics, so the idiomatic way of writing this would be something like:
//hyphens are not valid in identifiers
namespace ClassA
{
public class Human
{
// these properties are publicly gettable but can only be set privately
public string Name { get; private set; }
public int NetId { get; private set; }
public Human(string name, int netId)
{
this.Name = name;
this.NetId = netId;
}
// unlike Java, the entry-point Main method begins with a capital 'M'
public static void Main(string[] args)
{
Human human = new Human("Yoon Lee", 99);
int expected = human.NetId; // parantheses not required for property-getter
}
}
}
You're trying to use a method as if it's a property. You need parenthesis and to convert the string to int, or just make getNetID return an int.
I think you meant:
public int getNetID()
{
return netId;
}
Or better still, use automatic properties:
public int NetId {get; private set;} //Notice Making N in Net capital
And then:
int expected = human.getNetID();
This will do the trick (-:
It should be human.getNetID()
Edit: And yes, as Oren says - you should change your netId getter to return int. I assume that is what you want to do.
I see that netId is integer.
getNetID() return type is string.
return type is not matching.
netID is declared as an Int:
public int netId;
but your function getNetID returns a string:
public String getNetID()
Therefore, the body of getNetID makes no sense when it tried to return an int as a string:
return netId;
Human human = new Human("Yoon Lee", 99);
int expected = human.getNetID(); //<-gets the error at this moment.
you need to add parentheses after the method call.
The way you have it right now you are fetcing the function itself.

Is using an Enum the best way to go for listing different "Types of Car"

I have an attribute in my car class called VehicleType.
Using an enum, I could list the different types of cars that exist and not allow any other type to be hard written in.
Problem is, if I have to GET the attribute from somewhere else, I will GET a numberical value, and not the string literal I saved.
What should I use here?
class Hero
{
public string faction;
public string name;
public string herotype;
enum HeroType
{
Agility,
Strength,
Intelligence,
}
}
You could create an abstract base class
public abstract class BaseHero
{
public string faction;
public string name;
...... more properties
}
and then derive your heroes from that:
public class AgilityHero : BaseHero
{
}
public class StrengthHero : BaseHero
{
}
public class IntelligenceHero : BaseHero
{
}
Common stuff would be handled and coded in the base class, those things specific to a hero type in the actual hero class.
Using this OO approach, you can save yourself from having to write, code, maintain a lot of if....then.....else or switch statements in your Hero class - the differences are handled by the fact of having different types for each type of hero.
What? Why would you have a string literal and an enum? Your class should look like this:
class Hero
{
public string faction;
public string name;
public HeroType herotype; // <-- not a string
enum HeroType
{
Agility,
Strength,
Intelligence,
}
}
The "string" version is just the enum so it's easier for you to remember, but shouldn't actually be saved as a string anywhere (except if you need to display it to the user).
Whether an enum is approriate depends entirely on your design. If you have a fixed number of possible values, then an enum may be a good approach.
In C# you can convert between an Enumerated type and its string representation using Enum.ToString() and Enum.Parse(), so it is trivially easy to serialise an enum's value and disallow "illegal" values when reloading the data. There is no need to serialise it as an integer value.
(The one caveat of this is if you use obfuscation, you must make sure not to obfuscate the enumerated type)
If you have to store the enum as an integer value, then there is no problem with that, as long as you don't change the values of the enum entries - add new entries at the end of the enum's list, but don't insert new entries in the middle of it.
What I sometimes do for modeling richer 'enumeration-like' types is the following:
public enum HeroTypeValue
{
Agility,
Strength,
Intelligence
}
public class HeroType
{
public HeroTypeValue Value { get; set; }
public string Description { get; set; }
// ... other properties and possibly behaviour, as needed
public static HeroType Agility = new HeroType
{
ID = HeroTypeValue.Agility,
Description = "Agility"
},
public static HeroType Strength = new HeroType
{
ID = HeroTypeValue.Strength,
Description = "Agility"
};
public static HeroType Intelligence = new HeroType
{
ID = HeroTypeValue. Intelligence,
Description = "Intelligence"
};
public static IEnumerable<HeroType> All = new []
{
Agility,
Strength,
Intelligence
}
}
This allows to do data binding with easily customizable descriptions, when needed you can also synchronize with a table in the database.
You can of course combine it with the answer by marc_s, making the HeroType a (abstract or not) base class for added OO value.

Categories

Resources