Adding data to a generic string Array C# - c#

I'm learning about generics in C#, and I'm trying to make a generic array and add some strings to it. I can easily add int values to it, but I can't figure out how to make it work with strings. When I'm trying to use strings I get NullReferenceException.
I have a class called myArray, and it looks like this:
class MyArray<T> : IComparable<T>, IEnumerable<T>, IEnumerator<T>
{
T[] data = new T[10];
int current = -1;
public T[] Data
{
get { return data; }
}
public void Add(T value)
{
for (int i = 0; i < data.Length; i++)
{
if (data[i].Equals(default(T)))
{
data[i] = value;
return;
}
}
T[] tmp = new T[data.Length + 10];
data.CopyTo(tmp, 0);
Add(value);
}
In my mainform I add the data like this:
class Program
{
static void Main(string[] args)
{
MyArray<string> StringArray = new MyArray<string>();
StringArray.Add("ONE");
StringArray.Add("TWO");
}
}

The default of string is null as it is a reference type, not a value type. You are constructing a new array of type T[], which results in an array filled with the default value of T, which in this case is null.
Following that, data[i].Equals(default(T)) throws NRE as you are trying to call null.Equals(...).

Your array is being initialized with null values, so you're getting a NRE at this line:
if (data[i].Equals(default(T)))

if (data[i].Equals(default(T))) is where the issue lies. In a new string (or any other reference type) array,
var array = new String[10];
each element in the array is null by default. So when you say
data[i].Equals(default(T)
and data[i] is null, you're calling a method on a null reference, thus causing the exception to be thrown.
This doesn't happen for value types, as the array is initialized to the default value of whatever the value type is.
This is part of the problem with generics--you can't always treat reference types and value types the same.
Try this instead, to avoid default:
private int _currentIndex = 0;
public void Add(T value)
{
data[_currentIndex] = value;
_currentIndex++;
if(_currentIndex == data.Length)
{
T[] tmp = new T[data.Length + 10];
data.CopyTo(tmp, 0);
data = tmp;
_currentIndex = 0;
}
}

Related

How to store multiple datatype values into single list without defining class?

Expected result :
List<something> obj = new List<something>(); //something is i need.
string[] val = new string[] {"hi","20"}; //here I used static but input data fetch from CSV file. So we don't know when which type of data will come?.
int intval;
for(int i=0;i<val.Length;i++)
{
if(int.TryParse(val[i],out intval)
{
obj.add(intval); //here I face the error "Cannot implicitly convert int to string"
}
else
{
obj.add(val[i]);
}
}
I need to add int value and also string value into the same list. But The condition is Developer don't know when which type of value will come. So here I used TryParse to convert values and store into list.
How to declare a list or any other methods are there?
Note: Don't use Class to declare field and define like List<classname> val = new List<classname>();
Not sure why you want to do this but I think the code below is what you're looking for. I suppose you can later check if each list value typeof is string/int but why store multi value types in one list like this?
string[] val = new string[] { "hi", "20" };
List<object> objs = val.Select(x =>
{
if (int.TryParse(x, out var intval))
return (object)intval;
else
return (object)x;
}).ToList();
If you just need to store all the results that you get to a single list without caring about the type then dont Parse to int type like
for (int i = 0; i < val.Length; i++)
{
//simply add the
obj.add(val[i]);
}
Just use a List<object>. Every type ultimately derives from object:
List<object> obj = new List<object>();
string[] val = new string[] {"hi","20"};
for(int i = 0; i < val.Length; i++)
{
if(int.TryParse(val[i], out var intval)
{
obj.add(intval);
}
else
{
obj.add(val[i]);
}
}

Get input array of particular type

I need to get array input in particular types - example for int below.
string[] input = Console.ReadLine().Split(' ');
int[] array = new array[input.Length];
for(int i = 0; i < input.Length; i++)
{
array[i] = int.Parse(input[i]);
}
This is working, but in case of multiple such arrays of different type it takes up too much code to get input in string array and then parse it into required type for every input array.
Is there any shortcut way to get this done ?
It is guaranteed that complete array input will lie on single line.
Have a look at Enumerable.Select:
int[] array = input.Select(int.Parse).ToArray();
You could easily change this to another type, for example:
class StringContainer
{
public string Value { get; set; }
}
StringContainer[] array = input.Select(x => new StringContainer { Value = x }).ToArray();
You could even define an extension method:
public static TOut[] Convert<TIn, TOut>(this TIn[] input, Func<TIn, TOut> selector)
{
return input.Select(selector).ToArray();
}
Then use like this:
int[] intArray = input.Convert(int.Parse);
StringContainer[] scArray = input.Convert(x => new StringContainer { Value = x });
The type of the output array is inferred from the return type of the delegate.

C# Array of references to Variables and or Form objects

What I am trying to do is to have an array of references to variables. By which I mean the equivalent to a C array of pointers to ints (for example).
Example: (!!not real code!!)
int a = 4;
int b = 5;
int c = 6;
List<ref int> tmp = new List<ref int>();
tmp.Add(ref a);
tmp.Add(ref b);
tmp.Add(ref c);
tmp[0] = 16;
tmp[1] = 3;
tmp[2] = 1000;
Console.Writeline(tmp[0] + " " + a); // 16 16
Console.Writeline(tmp[1] + " " + b); // 3 3
Console.Writeline(tmp[2] + " " + c); // 1000 1000
The specifics of my case: I have a list of strings that will correspond to the keys in a dictionary. What I think I want to have is a list of Tuples where Type1 is a reference to either an int or string, and Type2 is a reference to an Textbox.
I will be iterating through this list, using the string to get the value from the dictionary (and doing stuff with that data) then storing the results of that into Type1. And eventually I will be taking the data from those Type1 variable references and copying their data to the corresponding Type2 Textbox.
That's the gist of what I think I want to do. If someone thinks that my approach is overly complicated, I will say that I need to keep the Textboxes as they are sadly, so I can't just make an array and iterate through it. And it would be perferable to keep the Type1 variables seperate too, though not quite as necessary.
Now, from reading around, I thought Func<> looked like it was the closest thing to being useful for what I want, so I tried to use the following (with Type1, as an object because it needs to handle both ints and strings)
List<Tuple<string, Func<object>, Func<object>>>
but I was unsure how to use that to get references to the variables.
What you're specifically asking for isn't possible; what would be more appropriate (and has the convenience of actually working!) would be to design a class structure around what you're trying to do.
For instance, something like this:
public class MyObject // Name it appropriately
{
public object Value { get; set; }
public string Key { get; set; }
public TextBox TextBox { get; set; }
}
Then, in your code, you can do something akin to this...
Dictionary<string, object> values = ...
List<MyObject> objects = ...
foreach(var item in objects)
{
item.Value = values[item.Key];
// process your data
item.TextBox = item.Value.ToString();
}
Obviously, this is just a rough design and the class here serves as little more than a data transfer container. You could make the class "smarter" by, for example, using the setter for the Value property to set the value of the TextBox automatically. But this should hopefully give you the general idea of how something like this would be done in an OO fashion.
EDIT Here's how your example would look.
MyObject a = new MyObject() { Value = 4 };
MyObject b = new MyObject() { Value = 5 };
MyObject c = new MyObject() { Value = 6 };
List<MyObject> tmp = new List<MyObject>();
tmp.Add(a);
tmp.Add(b);
tmp.Add(c);
tmp[0].Value = 16;
tmp[1].Value = 3;
tmp[2].Value = 1000;
Console.Writeline(tmp[0].Value.ToString() + " " + a.Value.ToString()); // 16 16
Console.Writeline(tmp[1].Value.ToString() + " " + b.Value.ToString()); // 3 3
Console.Writeline(tmp[2].Value.ToString() + " " + c.Value.ToString()); // 1000 1000
You can't store references using C#. You can only use the ref keyword when calling a method.
You can use pointers, but you can only do that with a fixed expression and within an unsafe context.
It is possible to fake this kind of thing using delegates, but I'm not sure if it's what you're looking for. I'm also fairly sure that you really need to redesign your approach, but nevertheless, here's an example of how you can fake it...
Firstly, write a "value wrapper" class like so:
public class ValueWrapper<T>
{
readonly Func<T> get;
readonly Action<T> set;
public ValueWrapper(Func<T> get, Action<T> set)
{
this.get = get;
this.set = set;
}
public T Value
{
get
{
return get();
}
set
{
set(value);
}
}
}
Then you can use that to change values:
void run()
{
int x = 0;
var intWrapper = new ValueWrapper<int>(() => x, value => x = value);
test(intWrapper);
Console.WriteLine(x); // Prints 42, which shows that x was changed.
TextBox textBox = new TextBox {Text = ""};
var stringWrapper = new ValueWrapper<string>(() => textBox.Text, value => textBox.Text = value);
test(stringWrapper);
Console.WriteLine(textBox.Text); // Prints "Changed".
}
static void test(ValueWrapper<int> wrapper)
{
wrapper.Value = 42;
}
static void test(ValueWrapper<string> wrapper)
{
wrapper.Value = "Changed";
}
You can also create a wrapper in one method and pass it to a different method which uses the wrapper to change a property in the original wrapped object, like so:
void run()
{
TextBox textBox = new TextBox {Text = ""};
var wrapper = test1(textBox);
test2(wrapper);
Console.WriteLine(textBox.Text); // Prints "Changed"
}
void test2(ValueWrapper<string> wrapper)
{
wrapper.Value = "Changed";
}
ValueWrapper<string> test1(TextBox textBox)
{
return new ValueWrapper<string>(() => textBox.Text, value => textBox.Text = value);
}
Warning: This does lead to some fairly head-scratching code, for example:
void run()
{
var intWrapper = test();
intWrapper.Value = 42;
Console.WriteLine(intWrapper.Value); // Works, but where is the value? It can't be the x inside test()!
}
ValueWrapper<int> test()
{
int x = 0;
var intWrapper = new ValueWrapper<int>(() => x, value => x = value);
return intWrapper;
}
So we returned a ValueWrapper from test() which is apparently wrapping a local variable from inside test(). And then we can apparently change the value and print it out...
This isn't really what's happening, of course, but it can be quite confusing!
you can use pointers in this case, use unsafe keyword for method and set project unsafe to allow pointers in c#, also you can encapsulate the value in a class and in C# each class is of reference type
i used this and works perfect:
exp.
public int value1 = 3;
public int value2 = 4;
public int value3 = 5;
public void Method1()
{
int[] values = { value1, value2, value3};
for (int i = 0; i < values.Length; i ++)
{
Console.WriteLine(values[i]);
}
}

Can a variant array be passed to C# using com interop?

I try to transfer some data between Excel and C#. For this I wrote a simple C# class with a property to set and get the data.
[Guid("xxx")]
[ClassInterface(ClassInterfaceType.AutoDual)]
[ComVisible(true)]
public class Vector
{
private object[,] _values;
public object[,] ExcelValues
{
get { ... }
set { ... }
}
}
Getting the ExcelValues property in VBA works well, but it is not possible to set it in VBA. The VBA code does not compile if I try to set the property:
Dim values As Variant
With myRange
' typo: Set values = Range(.Offset(0, 0), .Offset(100, 0))
values = Range(.Offset(0, 0), .Offset(100, 0))
End With
Dim data As New Vector
' this doesn't compile
data.ExcelValues = values
' this works
values = data.ExcelValues
Any suggestions how I can acomplish this, without setting each value from the variant Array one at a time?
I found a solution based on code that was posted here. A variant array has to be passed from VBA to C# as an object (not object[,]). Then it can be converted to something that is more handy by using reflection:
[Guid("xxx")]
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDual)]
public class Vector
{
[ComVisible(false)]
public IList<double> Values { get; set; }
public object[,] GetExcelValues()
{
// own extension method
return Values.ConvertToExcelColumn();
}
public void SetExcelValues(object comArray)
{
IEnumerable<object> values = ConvertExcelCloumnToEnumerable(comArray);
Values = new List<double>(values.Select(Convert.ToDouble));
}
private static IEnumerable<object> ConvertExcelCloumnToEnumerable(object comObject)
{
Type comObjectType = comObject.GetType();
if (comObjectType != typeof(object[,]))
return new object[0];
int count = (int)comObjectType.InvokeMember("Length", BindingFlags.GetProperty, null, comObject, null);
var result = new List<object>(count);
var indexArgs = new object[2];
for (int i = 1; i <= count; i++)
{
indexArgs[0] = i;
indexArgs[1] = 1;
object valueAtIndex = comObjectType.InvokeMember("GetValue", BindingFlags.InvokeMethod, null, comObject, indexArgs);
result.Add(valueAtIndex);
}
return result;
}
}
The other way - from C# to VBA - it can be passed more comfortable as object[,] or double[,].
Hope there are no syntax typos :).
By using Set you're telling VBA that "values" is an object (in this case a Range), but then you're not using set when assigning that to ExcelValues. Try dropping the Set when you're reading the values.
With myRange
values = Range(.Offset(0, 0), .Offset(100, 0)).Value
End With

nullable var using implicit typing in c#?

Is there anyway to have the var be of a nullable type?
This implicitly types i as an int, but what if I want a nullable int?
var i = 0;
Why not support this:
var? i = 0;
var is typed implicitly by the expression or constant on the right hand side of the assignment. var in and of itself is not a type so Nullable<var> is not possible.
Why support it? If that's what you mean, you should say var i = (int?)0; instead.
(Well, you should probably just say int? i = 0, but for more complicated types, etc.)
The problem deals with nullable types.
For instance, you cannot create a nullable string, which in turn prevents you from creating a nullable var, since var could be a string.
My answer is kind of along these lines. "var" is implicitly typed. It figures out what type it is by the value supplied on the right-hand side of the assignment. If you tell it that it's nullable it has no idea what type to be. Remember, once it's assigned, that's the type it's going to be forever.
Try this - is this what you're talking about?
static void Main(string[] args)
{
for (int i=0; i < 10; i++)
{
var j = testMethod();
if (j == null)
{
System.Diagnostics.Debug.WriteLine("j is null");
}
else
{
System.Diagnostics.Debug.WriteLine(j.GetType().ToString());
}
}
}
static int? testMethod()
{
int rem;
Math.DivRem(Convert.ToInt32(DateTime.Now.Millisecond), 2, out rem);
if (rem > 0)
{
return rem;
}
else
{
return null;
}
}
VAR is an implicit type determined by the compiler at the time of compilation. It is assigned upon first use. IE when you set var I = 1, var is an int because that is what the number 1 is. If you instead have var I = SomeFunction() where some function returns a nullable int than I will be set as int?. Now with that said var should not be used in a case where you want to control what the variable type is.
So bottom line, as per your example using var is wrong and should be explicitly set to int? from the start.
Darroll
I wouldn't even use var in this case. If it's a complex type or a simple one such as an int I would use type "object".
Example:
//Define all global class variables
List<int> m_lInts = New List<int>();
List<string> m_lStrs = New List<string>();
public static object FindMyObject(string sSearchCritera)
{
//Initialize the variable
object result = null;
if (result == null)
{
//Search the ints list
foreach(int i in m_lInts)
{
if (i.ToString() == sSearchCritera)
{
//Give it a value
result = (int)i;
}
}
}
if (result == null)
{
//Search the ints list
foreach(string s in m_lStrs)
{
if (s == sSearchCritera)
{
//Give it a value
result = (string)s;
}
}
}
//Return the results
return result;
}

Categories