Offset command in Revit API - c#

How can I use the offset command in my C# plugin? I have the list of lines/arcs to include in the offset and the offset value. I can't find the command to use.
I thought that the ElementTransformUnit class contains something to do it but it seems that it doesn't...
Thank you

There's no Offset command that I'm aware of, but you could make one pretty easily I think using the ElementTransformUtils.CopyElement method instead. Try something like this:
static ElementId Offset(this Element originalelement, double offsetamount, string offsetdirection)
{
ElementId newelement = null;
Document curdoc = originalelement.Document;
LocationPoint elp = originalelement.Location as LocationPoint;
XYZ elem_location = null;
switch(offsetdirection.ToUpper())
{
default:
break;
case "X":
elem_location = new XYZ(offsetamount, 0.0, 0.0) + elp.Point;
break;
case "Y":
// code for Y
break;
case "Z":
// code for Z
break;
}
try
{
using (Transaction tr_offset = new Transaction(curdoc, "Offsetting element"))
{
tr_offset.Start();
newelement = ElementTransformUtils.CopyElement(curdoc, originalelement.Id, elem_location).FirstOrDefault();
tr_offset.Commit();
}
}
catch (Exception e)
{
Console.WriteLine("Command Failed. See below: \n" + e.StackTrace.ToString());
}
return newelement;
}
might be better if you made a Direction enum or something like that but that should work for your purposes, I think.

Related

How to use "using static" directive for dynamically generated code?

I want to let the users input mathematics expression in terms of x and y as natural as possible. For example, instead of typing Complex.Sin(x), I prefer to use just Sin(x).
The following code fails when Sin(x), for example, is defined by the user.
using Microsoft.CodeAnalysis.CSharp.Scripting;
using System;
using System.Numerics;
using static System.Console;
using static System.Numerics.Complex;
namespace MathEvaluator
{
public class Globals
{
public Complex x;
public Complex y;
}
class Program
{
async static void JobAsync(Microsoft.CodeAnalysis.Scripting.Script<Complex> script)
{
Complex x = new Complex(1, 0);
Complex y = new Complex(0, 1);
try
{
var result = await script.RunAsync(new Globals { x = x, y = y });
WriteLine($"{x} * {y} = {result.ReturnValue}\n");
}
catch (Exception e)
{
WriteLine(e.Message);
}
}
static void Main(string[] args)
{
Console.Write("Define your expression in x and y: ");
string expression = Console.ReadLine(); //user input
var script = CSharpScript.Create<Complex>(expression, globalsType: typeof(Globals));
script.Compile();
JobAsync(script);
}
}
}
Question
How to use using static directive for dynamically generated code?
You can supply script options to the Create function that define the references and imports that should be set for your script:
var scriptOptions = ScriptOptions.Default
.WithReferences("System.Numerics")
.WithImports("System.Numerics.Complex");
var script = CSharpScript.Create<Complex>(expression, options: scriptOptions, globalsType: typeof(Globals));
That way, you can use Sin(x) in the input:
Define your expression in x and y: Sin(x)
(1, 0) * (0, 1) = (0,841470984807897, 0)
However, when dealing with user input, you should consider writing your own parser. This allows you on one hand to define your own “aliases” for functions (e.g. a lower case sin) or even a more lenient syntax; on the other hand, it also adds more security because right now, nothing prevents me from doing this:
Define your expression in x and y: System.Console.WriteLine("I hacked this calculator!")
I hacked this calculator!
(1, 0) * (0, 1) = (0, 0)
I created a quick (and dirty) parser using Roslyn’s syntax tree parsing. Obviously this is rather limited (e.g. since it requires all return values of subexpressions to be Complex), but this could give you an idea of how this could work:
void Main()
{
string input = "y + 3 * Sin(x)";
var options = CSharpParseOptions.Default.WithKind(Microsoft.CodeAnalysis.SourceCodeKind.Script);
var expression = CSharpSyntaxTree.ParseText(input, options).GetRoot().DescendantNodes().OfType<ExpressionStatementSyntax>().FirstOrDefault()?.Expression;
Console.WriteLine(EvaluateExpression(expression));
}
Complex EvaluateExpression(ExpressionSyntax expr)
{
if (expr is BinaryExpressionSyntax)
{
var binExpr = (BinaryExpressionSyntax)expr;
var left = EvaluateExpression(binExpr.Left);
var right = EvaluateExpression(binExpr.Right);
switch (binExpr.OperatorToken.ValueText)
{
case "+":
return left + right;
case "-":
return left - right;
case "*":
return left * right;
case "/":
return left / right;
default:
throw new NotSupportedException(binExpr.OperatorToken.ValueText);
}
}
else if (expr is IdentifierNameSyntax)
{
return GetValue(((IdentifierNameSyntax)expr).Identifier.ValueText);
}
else if (expr is LiteralExpressionSyntax)
{
var value = ((LiteralExpressionSyntax)expr).Token.Value;
return float.Parse(value.ToString());
}
else if (expr is InvocationExpressionSyntax)
{
var invocExpr = (InvocationExpressionSyntax)expr;
var args = invocExpr.ArgumentList.Arguments.Select(arg => EvaluateExpression(arg.Expression)).ToArray();
return Call(((IdentifierNameSyntax)invocExpr.Expression).Identifier.ValueText, args);
}
else
throw new NotSupportedException(expr.GetType().Name);
}
Complex Call(string identifier, Complex[] args)
{
switch (identifier.ToLower())
{
case "sin":
return Complex.Sin(args[0]);
default:
throw new NotImplementedException(identifier);
}
}
Complex GetValue(string identifier)
{
switch (identifier)
{
case "x":
return new Complex(1, 0);
case "y":
return new Complex(0, 1);
default:
throw new ArgumentException("Identifier not found", nameof(identifier));
}
}

How to pass property as a parameter in order to use the same function to modify different properties

I've found similar questions asked before but the answers I've seen have been specific to the example given by the person or workarounds for that person's example, not a general solution.
I'd like to pass a class' property to a function to do an operation on that property. The example I'm going to use is incrementing a value, but I have more complicated scenarios so I'm looking for a general solution, not an answer for specifically incrementing.
How I used to do it is I'd either have multiple functions IncrementPassengerCount, IncrementDistanceTravelled, IncrementPlaneAge, but that's unweildly and horrible.
I'd like one general function that I can call using something like this pseudocode:
Increment(myPlane, myPlane.DistanceTravelled);
Increment(myPlane, myPlane.PlaneAge);
//where
public void Increment(Airplane myPlane, Property propToIncrement)
{
myPlane.propToIncrement++; //or do whatever like I now have myPlane.DistanceTravelled
}
I've tried this:
Increment(myPlane, x => x.DistanceTravelled);
//where
public void Increment(Airplane myPlane, Func<Log, IComparable> property)
{
property(myPlane)++;
}
But this causes a
Operator '++' cannot be applied to operand of type 'System.IComparable'
Is there a way to do what I'm imagining or am I looking at it wrong? Thanks in advance.
Is is possible, though convoluted and probably a sign that you should perhaps do it a different way, but here it is. (I would recommend as Jon Skeet mentioned, to just use the ++ operator instead of invoking the Increment method. In addition to the method I included two classes that will allow you to test the code in a console app. There would need to be plenty of error checking. I have a few null checks, but there may be more locations it is needed. If you have overloaded the ++ operator, it works for those types too, but any errors cannot be anticipated.
public static void Increment(this object o, string propertyName)
{
var property = o.GetType().GetProperty(propertyName);
if (property == null)
return;
var val = property.GetValue(o, null);
var op_Inc = o.GetType().GetMethod("op_Increment");
if(op_Inc != null)
{
var val2 = op_Inc.Invoke(val, null);
property.SetValue(o,val2);
}
switch (Type.GetTypeCode(property.PropertyType))
{
case TypeCode.UInt16:
{
var x = (UInt16)val;
x++;
property.SetValue(o, x);
}
break;
case TypeCode.UInt32:
{
var x = (UInt32)val;
x++;
property.SetValue(o, x);
}
break;
case TypeCode.UInt64:
{
var x = (UInt64)val;
x++;
property.SetValue(o, x);
}
break;
case TypeCode.Int16:
{
var x = (Int16)val;
x++;
property.SetValue(o, x);
}
break;
case TypeCode.Int32:
{
var x = (Int32)val;
x++;
property.SetValue(o, x);
}
break;
case TypeCode.Int64:
{
var x = (Int64)val;
x++;
property.SetValue(o, x);
}
break;
case TypeCode.Decimal:
{
var x = (Decimal)val;
x++;
property.SetValue(o, x);
}
break;
case TypeCode.Double:
{
var x = (Double)val;
x++;
property.SetValue(o, x);
}
break;
case TypeCode.Single:
{
var x = (Single)val;
x++;
property.SetValue(o, x);
}
break;
}
}
}
public class Example
{
public static void Main()
{
var plane = new Plane(){DistanceTravelled = 0, PlaneAge = 0};
Console.WriteLine("Before invoking increment: dist = {0}, age = {1}", plane.DistanceTravelled, plane.PlaneAge);
plane.Increment("DistanceTravelled");
plane.Increment("PlaneAge");
Console.WriteLine("After invoking increment: dist = {0}, age = {1}", plane.DistanceTravelled, plane.PlaneAge);
Console.ReadKey();
}
}
public class Plane
{
public int DistanceTravelled { get; set; }
public int PlaneAge { get; set; }
}

C# Long Switch Statements

I've seen the articles on StackOverflow regarding c++ long switch statements, but c# is different in this regard.
Specifically, I would like to replace a hugely-long switch statement in c# code, where each case statement does the same thing, just the field name changes.
The code looks like this:
case Fields.TRANSMITTERCONTACTPHONEEXT:
{
int lengthNeeded = 0;
int currentLength = TransmitterContactTelephoneExtension.Length;
int lengthRequired = TransmitterContactTelephoneExtensionLength;
if (currentLength < lengthRequired)
{
lengthNeeded = lengthRequired - currentLength;
for (int i = 0; i < lengthNeeded; i++)
{
TransmitterContactTelephoneExtension += " ";
}
}
} break;
case Fields.TRANSMITTERFEIN:
{
int lengthNeeded = 0;
int currentLength = TransmitterFEIN.Length;
int lengthRequired = TransmitterFEINLength;
if (currentLength < lengthRequired)
{
lengthNeeded = lengthRequired - currentLength;
for (int i = 0; i < lengthNeeded; i++)
{
TransmitterFEIN += " ";
}
}
} break;
I'd like to just get this down to a single function that can figure out which field I mean without having to use a switch statement. Is there a way to pass in a variable containing the field name?
Place all the changeable values into arrays and index into it. Make sure the enum int values are the same as the data in the target arrays.
var current = (int) Fields.TRANSMITTERCONTACTPHONEEXT;
int lengthNeeded = 0;
int currentLength = LengthData[ current ] ;
int lengthRequired = RequiredData[current ];
if (currentLength < lengthRequired)
{
lengthNeeded = lengthRequired - currentLength;
for (int i = 0; i < lengthNeeded; i++)
{
Extensions[ current ] = Extensions[ current ] + " ";
}
}
This post looks at the pattern of the operations in the switch and does not address any localized deficiencies of individual operations. Please look at each of the individual operations and where needed improve it for optimal operational efficiencies.
This just looks like the code for a string pad function repeated multiple times. You could just have
case Fields.TRANSMITTERCONTACTPHONEEXT:
TransmitterContactTelephoneExtension = TransmitterContactTelephoneExtension.PadRight(TransmitterContactTelephoneExtensionLength, ' ');
break;
...
Any time that you find yourself repeating code over and over, you probably can break it out into a separate function (if one does not already exist) and just call it with the right parameters.
And this also makes me wonder if you need the switch case statement at all, and not just a series of pad statements. But that is going further out (in scope) in your code. And your post does not give us enough info to go there.
Finally, somewhat applicable to your question, my rule of thumb (not originally mine, but I forget where I got it) is that if a method is more than a pageful (intentionally vague term), then I need to break it up into other separate methods. That allows me to look at a method and understand it without scrolling around. It also forces me to separate a longer process into smaller logical steps.
You really should break this out into a method. So that you are not duplicating code over and over. That is inefficient and can lead to potential errors when updating.
Also instead of looping you should make use of the PadRight() method on strings.
I would do this:
case Fields.TRANSMITTERCONTACTPHONEEXT:
TransmitterContactTelephoneExtension = PadString(TransmitterContactTelephoneExtensionLength, TransmitterContactTelephoneExtension);
break;
case Fields.TRANSMITTERFEIN:
TransmitterFEIN = PadString(TransmitterFEINLength, TransmitterFEIN);
break;
private string PadString(int requiredLen, string value)
{
if (value == null) return String.Empty.PadRight(requiredLen, ' '); //Create an empty string when the value is null
return value.PadRight(requiredLen, ' ');
}
Declare the variables in advance, and use the switch only for the assignments that differ:
int currentLength;
int lengthRequired;
switch (whatever) {
case Fields.TRANSMITTERCONTACTPHONEEXT:
currentLength = TransmitterContactTelephoneExtension.Length;
lengthRequired = TransmitterContactTelephoneExtensionLength;
break;
case Fields.TRANSMITTERFEIN:
currentLength = TransmitterFEIN.Length;
lengthRequired = TransmitterFEINLength;
break;
default:
throw new Exception(); // Without this, the compiler will complain about uninitialized variables
}
int lengthNeeded = 0;
if (currentLength < lengthRequired)
{
lengthNeeded = lengthRequired - currentLength;
for (int i = 0; i < lengthNeeded; i++)
{
TransmitterFEIN += " ";
}
}
switch (whatever) {
case Fields.TRANSMITTERCONTACTPHONEEXT:
TransmitterContactTelephoneExtension += " ";
break;
case Fields.TRANSMITTERFEIN:
TransmitterFEIN += " ";
break;
}
Edit: OmegaMan's solution is way better if you have the option of replacing the variables with an array.
To me it seems like the code we can't see needs some refactoring, but based on what we can see, I would recommend doing the following:
// 1. Have a class to hold your data
class FieldData
{
public string Value { get; set; }
public int LengthRequired { get; set; }
public string RightPaddedValue
{
get { return Value.PadRight(LengthRequired, ' '); }
}
}
// 2. Fill your data into a dictionary somehow... for example:
Dictionary<Fields, FieldData> fields = new Dictionary<Fields, FieldData>
{
{
Fields.TRANSMITTERCONTACTPHONEEXT,
new FieldData {
Value = TransmitterContactTelephoneExtension,
LengthRequired = TransmitterContactTelephoneExtensionLength
}
},
{
Fields.TRANSMITTERFEIN,
new FieldData {
Value = TransmitterFEIN,
LengthRequired = TransmitterFEINLength
}
}
};
// 3. Then use the data from that dictionary in your code:
FieldData data = fields[selectedField];
data.RightPaddedValue; // use RightPaddedValue

Move switch statement to text file

Here is my situation every time we add a new product to our catalog we need to go through add the product to this snippet and recompile the dll's, then push them out to all of the servers.
What I'd like to be able to do is to be able to just add a line to a text file that the DLL then reads in. To make things easy the file will reside in the same folder as the DLL's. The main issue is there are several places that call this all of which pass in the productId, so changing that would not be feasible.
void AssignFunctions(int productId)
{
switch (productId)
{
case 31:
IsSpread = CalendarIsSpread;
IsLeftPage = CalendarIsLeftPage;
GetOppositePageNumber = GeneralGetOppositePageNumber;
break;
case 49:
case 63:
case 64:
case 69:
case 70:
...
case 592:
case 630:
case 686:
IsSpread = NeverASpread;
IsLeftPage = GeneralIsLeftPage;
GetOppositePageNumber = GeneralGetOppositePageNumber;
break;
case 73:
IsSpread = GeneralIsSpread;
IsLeftPage = GeneralIsLeftPage;
GetOppositePageNumber = GeneralGetOppositePageNumber;
break;
case 444:
case 445:
IsSpread = BookletIsSpread;
IsLeftPage = BookletLeftPage;
GetOppositePageNumber = BookletGetOppositePageNumber;
break;
default:
IsSpread = GeneralIsSpread;
IsLeftPage = GeneralIsLeftPage;
GetOppositePageNumber = GeneralGetOppositePageNumber;
break;
}
}
Another scenario would be to take the productId and compare it to the text file and then act accordingly. In that case the call would look something like this:
void AssignFunctions(int productId)
{
//Do Something here to get the productSpreadType
switch (productSpreadType)
{
case 1:
IsSpread = CalendarIsSpread;
IsLeftPage = CalendarIsLeftPage;
GetOppositePageNumber = GeneralGetOppositePageNumber;
break;
case 2:
IsSpread = NeverASpread;
IsLeftPage = GeneralIsLeftPage;
GetOppositePageNumber = GeneralGetOppositePageNumber;
break;
case 3:
IsSpread = GeneralIsSpread;
IsLeftPage = GeneralIsLeftPage;
GetOppositePageNumber = GeneralGetOppositePageNumber;
break;
case 4:
IsSpread = BookletIsSpread;
IsLeftPage = BookletLeftPage;
GetOppositePageNumber = BookletGetOppositePageNumber;
break;
default:
IsSpread = GeneralIsSpread;
IsLeftPage = GeneralIsLeftPage;
GetOppositePageNumber = GeneralGetOppositePageNumber;
break;
}
}
In this case the text file would look something like this:
31 1
49 2
63 2
...
73 3
444 4
If the productId is not listed it would just then perform the default action.
.NET is not my forte and it takes a good half day every time we add new products to remember how to update this. As I am the only one with Visual Studio running on Windows the task always fall to me. With the exception of having to make this change we don't have to touch the code base, so it would be nice to not have to build the DLL's every time and be able to pass the task of making sure this gets updated to one of our junior developers, who make are the ones responsible for adding new products.
C# is a static language and is not meant for dynamic code like you're suggesting.
I would however consider a different design where you can read different categories from a database and act on them as categories rather than individual items with the same handling.
Looks like you can group a lot of these together.
You can also consider a config file as the source for the categories.
You could use a little reflection magic:
using System;
using System.Linq;
using System.Reflection;
public class Program
{
public static void Main()
{
// Test Data
DoProduct(31);
DoProduct(63);
DoProduct(49);
DoProduct(49);
DoProduct(61);
}
public static void DoProduct(int productId)
{
string data = "";
bool methodExecuted = false;
// I am loading the string "data" with test data for simplicity.
// In real life, you'll load this from your file intead.
data = data + "31 MyFirstFunction" + Environment.NewLine;
data = data + "49 MySecondFunction" + Environment.NewLine;
data = data + "63 MyThirdFunction" + Environment.NewLine;
foreach (string str in data.Replace(Environment.NewLine, "\n").Replace('\r', '\n').Split('\n'))
{
if (string.IsNullOrEmpty(str))
continue;
int pid = int.Parse(str.Split(' ')[0]);
string func = str.Split(' ')[1];
if (pid != productId)
continue;
Type type = typeof(Program);
MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public);
MethodInfo method = methods.FirstOrDefault(z => z.Name.Equals(func));
if (method == null) {
continue;
}
method.Invoke(null, null);
methodExecuted = true;
}
if (!methodExecuted)
{
MyDefaultFunction();
}
}
public static void MyFirstFunction()
{
Console.WriteLine("This is MyFirstFunction()!");
}
public static void MySecondFunction()
{
Console.WriteLine("This is MySecondFunction()!");
}
public static void MyThirdFunction()
{
Console.WriteLine("This is MyThirdFunction()!");
}
public static void MyDefaultFunction()
{
Console.WriteLine("This is MyDefaultFunction()!");
}
}
This will allow you to create a text file, like this:
31 MyFunction
63 AnotherFunction
...
And using reflection, it will execute the correct function every time you pass in a product id. If the product id is not in the text file, it will call the default function.
Here is a fiddle of it in action: https://dotnetfiddle.net/7Atpq7
If you really must use a text file you could load it into a multiple value dictionary using a struct, then perform a search on that dictionary
assuming test data of the following in a text file called test.txt:
1,value1,value2
2,value1,value2
...
you could do something like this:
class Program
{
// declare test data
public static int[] _products = new int[] { 1, 2, 3, 4, 5 };
// Searchable value dictionary to be filled by file
static Dictionary<int,Values> d = new Dictionary<int,Values>();
static void Main(string[] args)
{
// Read the file line by line into the dictionary
string line;
System.IO.StreamReader file =
new System.IO.StreamReader("c:\\test\\test.txt");
while ((line = file.ReadLine()) != null)
{
string[] values = line.Split(',');
int productId = int.Parse(values[0]);
Values v = new Values();
v.Value1 = values[1];
v.Value2 = values[2];
d.Add(productId, v);
}
file.Close();
// check our loaded config file
foreach (int p in _products)
{
if (d.Keys.Contains(p))
{
// we've found a match in the file
// your logic goes here!
}
else
{
// no match was found
// handle missing data
}
}
}
// struct to hold your data from text file
struct Values
{
public string Value1;
public string Value2;
}
}

Trouble finding tab character in list objects

I am working in C#, winforms application.
I am reading from a text file where each row has fields divided by tabs:
I am putting each row in a list named tic_string. From here I am trying to search each list object, find the tabs, and put each field in its own array. So there will be an array for column a, column b, column c ... etc.
The problem is when I try to find the tabs in my list objects, it finds nothing. Here is my code:
string[] tic_num = new string[row_counter];
string[] tic_title = new string[row_counter];
string[] tic_owner = new string[row_counter];
string[] tic_open_date = new string[row_counter];
int last_tab = 0;
int char_counter = 0;
int feild_counter = 1;
int feild_char_count = 1;
int current_row=0;
string temp_feild = "";
char temp_char;
char tab_char = '\t';
foreach (string tic_string_value in tic_string)
{
temp_char = tic_string_value[char_counter];
if (temp_char == tab_char)
{
Console.WriteLine("tab_found");
if (feild_char_count == 1)
{
temp_feild = "";
}
else
{
temp_feild = tic_string_value.Substring(last_tab, feild_char_count);
}
last_tab = char_counter;
feild_char_count = 0;
switch (feild_counter)
{
case 1:
tic_num[current_row] = temp_feild;
break;
case 2:
tic_title[current_row] = temp_feild;
break;
case 3:
tic_owner[current_row] = temp_feild;
break;
case 4:
tic_open_date[current_row] = temp_feild;
break;
}
}
current_row++;
feild_char_count++;
char_counter++;
if (feild_counter == 5)
feild_counter = 1;
}
Your code seems to be too complicated for such simple task. Do not parse each line char by char, just use helper functions like String.Split etc.:
foreach (string tic_string_value in tic_string)
{
var parts = tic_string_value.Split(new [] { '\t' },
StringSplitOptions.RemoveEmptyEntries);
tic_num[current_row] = parts[0];
tic_title[current_row] = parts[1];
tic_owner[current_row] = parts[2];
tic_open_date[current_row] = parts[3];
current_row++;
}
First of all, I deduce from the style of your code that you are probably familiar with C/C++ and are new to C#, because this code has a particularly "C++" flavour to it. It reminds me very much of my own C# code when I first made the jump myself.
I am glad that you described the problem you are trying to solve rather than simply posting the code and asking where to find the bug because I think you can actually solve your problem much more simply.
Considering the following code (this assumes that you're iterating over each of the rows outside this code, and I omit some of the declaring of variables that you had already specified):
int field_counter = 0;
foreach (var field in tic_string.Split('\t')) {
switch (field_counter++) {
case 0:
tic_num[current_row] = field;
break;
case 1:
tic_title[current_row] = field;
break;
case 2:
tic_owner[current_row] = field;
break;
case 3:
tic_open_date[current_row] = field;
break;
}
}
This leverages the succinctness of C# and removes quite a few lines of code, which is always good. The String.Split method will take care of most of the string splitting for you, so there's no need to do it all manually and keep track of characters.
Note: I kept your original naming of some of the field names, although generally it is preferable to use CamelCase in C# code.
Now I notice from your original code that it's possible you don't have "rows" in your data in an actual sense (i.e. split by newline characters) but rather you may have the data entirely tab separated and are using the fact that you have a fixed number of columns per row to split up rows.
If this was the case, might I suggest the following code block could help you:
int i = 0;
foreach (var group in tic_string.GroupBy(x => i++ % 4)) {
int current_row = 0;
foreach (var field in group) {
switch (group.Key) {
case 0:
tic_num[current_row] = field;
break;
case 1:
tic_title[current_row] = field;
break;
case 2:
tic_owner[current_row] = field;
break;
case 3:
tic_open_date[current_row] = field;
break;
}
current_row++;
}
}
Now of course you may need to adapt these blocks to your code rather than use it verbatim. I hope that they at least demonstrate a different way of thinking about the problem. In particular, learning to use the various LINQ extension methods and LINQ queries will also be very helpful - they are part of what allows C# code to be so quick and easy to develop.
Best of luck in solving your problem!
You could also use a list instead of 4 string arrays:
public class ObjectToBeUsed
{
public Person(int num, string title, string owner, string opendate)
{
this.Num = num;
this.Title = title;
this.Owner = owner;
this.OpenDate = opendate;
}
private int _num;
public int Num
{
get { return _num; }
set { _num = value; }
}
private string _title;
public string Title
{
get { return _title; }
set { _title = value; }
}
private string _owner;
public string Owner
{
get { return _owner; }
set { _owner = value; }
}
private string _opendate;
public string OpenDate
{
get { return _opendate; }
set { _opendate = value; }
}
}
This is the class which describes each row in your text file.
System.IO.StreamReader file = new System.IO.StreamReader("test.txt");
string currentLine = null;
List<ObjectToBeUsed> peopleList = new List<ObjectToBeUsed>();
while ((currentLine = file.ReadLine()) != null)
{
string[] tokens = Regex.Split(currentLine, #"\t");
peopleList.Add(new ObjectToBeUsed(Convert.ToInt32(tokens[0]), tokens[1], tokens[2], tokens[3]));
}
The code is pretty self-explanatory, but if you need any further explaining, go ahead.

Categories

Resources