I am trying to make a generic method, that adds an object to the given array.
I tried the below code, but I get this error: "A property, indexer or dynamic member access may not be passed as an out or ref parameter"
public void Main()
{
Foo newObject = new Foo();
AddObjectToArray<Foo>(ref _allMyData.FooArray, newObject);
}
public void AddObjectToArray<T>(ref T[] array, T newObject)
{
var list = array.ToList();
list.Add(newObject);
array = list.ToArray();
}
I could solve it by removing the ref and returning the array like this:
_allMyData.FooArray = AddObjectToArray<Foo>(_allMyData.FooArray, newObject);
But it would be much cleaner if I could only use the ref :-)
Am I missing something obvious?
You can't use a property for the ref parameter. You would need to get the reference out, make the call, and put it back:
Foo[] arr = _allMyData.FooArray;
AddObjectToArray<Foo>(ref arr, newObject);
_allMyData.FooArray = arr;
So, you might want to reconsider using an array in the first place. Adding items to an array is very inefficient anyway, as you have to copy the entire array content each time.
Related
Basically I am trying to wrap a IEnumerable with a generic array and still be able to modify the values in the original collection, this works fine for reference types when I am just modifying their internal fields, but when using value types or trying to replace elements it does not appear to work.
For example:
// Original enumerable
var test = new List<int>(new int[] {
1,
2,
3
});
// Array wrapper
var test2 = test.ToArray();
test2[0] = 100; // Does not change test[0]
// Don't want to use pointers, but as a test
unsafe
{
int* test3 = &test2[0];
*test3 = 100; // Still does not change test[0]
}
So I was wondering if there is someway to create an array wrapper of a value type IEnumerable that will allow the original collection values to be modified?
The reason I need to do this is the classes are being shared with FORTRAN95 code and due to limited compiler support for .NET arrays I can not anything that does not inherit from System.Array
Enumerable.ToArray() doesn't "wrap" the enumerable in an array: it iterates over the enumerable, creating an array. It's pretty much the equivalent of this:
public static T[] ToArray<T>( this IEnumerable<T> source )
{
List<T> list = new List<T>() ;
foreach( T item in source )
{
list.Add(item) ;
}
T[] value = list.ToArray() ;
return value ;
}
So if you do something like this:
int[] foo = PopulateSource() ;
int[] bar = foo.ToArray() ; // Enumerable.ToArray()
saying
foo[3] = int.MinValue ;
won't affect bar[3] in the least, regardless of whether or not the array contains value types or reference types.
However, if you're using reference types,
Widget[] foo = PopulateSource() ;
Widget[] bar = foo.ToArray() ; // Enumerable.ToArray()
and saying something like
foo[3].Gadget = new Gadget("Pancake Turner") ;
then the change will be reflected in both foo[3] and bar[3], because both array slots are references to the same instance of Widget.
Further, you can't wrap something in an array, because even though System.Array is not sealed:
public abstract class Array :
ICloneable, IList, ICollection, IEnumerable,
IStructuralComparable, IStructuralEquatable
it is a special class and cannot be inherited from. So something like this:
class Widget : System.Array
{
}
Yields this compiler error
error CS0644: 'ConsoleApplication2.Program.Widget' cannot derive from special class 'System.Array'
What you can do is create a wrapper for your original object that gives array-like semantics, implementing IList and IList<T>.
I have a third party library returning an object array of object arrays that I can stuff into an object[]:
object[] arr = myLib.GetData(...);
The resulting array consists of object[] entries, so you can think of the return value as some kind of recordset with the outer array representing the rows and the inner arrays containing the field values where some fields might not be filled (a jagged array). To access the individual fields I have to cast like:
int i = (int) ((object[])arr[row])[col];//access a field containing an int
Now as I'm lazy I want to access the elements like this:
int i = (int) arr[row][col];
To do this I use the following Linq query:
object[] result = myLib.GetData(...);
object[][] arr = result.Select(o => (object[])o ).ToArray();
I tried using a simple cast like object[][] arr = (object[][])result; but that fails with a runtime error.
Now, my questions:
Is there a simpler way of doing this? I have the feeling that some
nifty cast should do the trick?
Also I am worried about performance
as I have to reshape a lot of data just to save me some casting, so I
wonder if this is really worth it?
EDIT:
Thank you all for the speedy answers.
#James: I like your answer wrapping up the culprit in a new class, but the drawback is that I always have to do the Linq wrapping when taking in the source array and the indexer needs both row and col values int i = (int) arr[row, col]; (I need to get a complete row as well like object[] row = arr[row];, sorry didn't post that in the beginning).
#Sergiu Mindras: Like James, i feel the extension method a bit dangerous as it would apply to all object[] variables.
#Nair: I chose your answer for my implementation, as it does not need using the Linq wrapper and I can access both individual fields using int i = (int) arr[row][col]; or an entire row using object[] row = arr[row];
#quetzalcoatl and #Abe Heidebrecht: Thanks for the hints on Cast<>().
Conclusion: I wish I could choose both James' and Nair's answer, but as I stated above, Nair's solution gives me (I think) the best flexibility and performance.
I added a function that will 'flatten' the internal array using the above Linq statement because I have other functions that need to be fed with such a structure.
Here is how I (roughly) implemented it (taken from Nair's solution:
public class CustomArray
{
private object[] data;
public CustomArray(object[] arr)
{
data = arr;
}
//get a row of the data
public object[] this[int index]
{ get { return (object[]) data[index]; } }
//get a field from the data
public object this[int row, int col]
{ get { return ((object[])data[row])[col]; } }
//get the array as 'real' 2D - Array
public object[][] Data2D()
{//this could be cached in case it is accessed more than once
return data.Select(o => (object[])o ).ToArray()
}
static void Main()
{
var ca = new CustomArray(new object[] {
new object[] {1,2,3,4,5 },
new object[] {1,2,3,4 },
new object[] {1,2 } });
var row = ca[1]; //gets a full row
int i = (int) ca[2,1]; //gets a field
int j = (int) ca[2][1]; //gets me the same field
object[][] arr = ca.Data2D(); //gets the complete array as 2D-array
}
}
So - again - thank you all! It always is a real pleasure and enlightenment to use this site.
You could create a wrapper class to hide the ugly casting e.g.
public class DataWrapper
{
private readonly object[][] data;
public DataWrapper(object[] data)
{
this.data = data.Select(o => (object[])o ).ToArray();
}
public object this[int row, int col]
{
get { return this.data[row][col]; }
}
}
Usage
var data = new DataWrapper(myLib.GetData(...));
int i = (int)data[row, col];
There is also the opportunity to make the wrapper generic e.g. DataWrapper<int>, however, I wasn't sure if your data collection would be all of the same type, returning object keeps it generic enough for you to decide what data type cast is needed.
There are few similar answer posted which does something similar. This differ only if you want to acess like
int i = (int) arr[row][col];
To demonstrate the idea
public class CustomArray
{
private object[] _arr;
public CustomArray(object[] arr)
{
_arr = arr;
}
public object[] this[int index]
{
get
{
// This indexer is very simple, and just returns or sets
// the corresponding element from the internal array.
return (object[]) _arr[index];
}
}
static void Main()
{
var c = new CustomArray(new object[] { new object[] {1,2,3,4,5 }, new object[] {1,2,3,4 }, new object[] {1,2 } });
var a =(int) c[1][2]; //here a will be 4 as you asked.
}
}
(1) This probably could be done in short and easy form with dynamic keyword, but you'll use compile-time checking. But considering that you use object[], that's a small price:
dynamic results = obj.GetData();
object something = results[0][1];
I've not checked it with a compiler though.
(2) instead of Select(o => (type)o) there's a dedicated Cast<> function:
var tmp = items.Select(o => (object[])o).ToArray();
var tmp = items.Cast<object[]>().ToArray();
They are almost the same. I'd guess that Cast is a bit faster, but again, I've not checked that.
(3) Yes, reshaping in that way will affect the performance somewhat, depending mostly on the amount of items. The impact will be the larger the more elements you have. That's mostly related to .ToArray as it will enumerate all the items and it will make an additional array. Consider this:
var results = ((object[])obj.GetData()).Cast<object[]>();
The 'results' here are of type IEnumerable<object[]> and the difference is that it will be enumerated lazily, so the extra iteration over all elements is gone, the temporary extra array is gone, and also the overhead is minimal - similar to manual casting of every element, which you'd do anyways.. But - you lose the ability to index over the topmost array. You can loop/foreach over it, but you cannot index/[123] it.
EDIT:
The James's wrapper way is probably the best in terms of overall performance. I like it the most for readability, but that's personal opinion. Others may like LINQ more. But, I like it. I'd suggest James' wrapper.
You could use extension method:
static int getValue(this object[] arr, int col, int row)
{
return (int) ((object[])arr[row])[col];
}
And retrieve by
int requestedValue = arr.getValue(col, row);
No idea for arr[int x][int y] syntax.
EDIT
Thanks James for your observation
You can use a nullable int so you don't get an exception when casting.
So, the method will become:
static int? getIntValue(this object[] arr, int col, int row)
{
try
{
int? returnVal = ((object[])arr[row])[col] as int;
return returnVal;
}
catch(){ return null; }
}
And can be retrieved by
int? requestedValue = arr.getIntValue(col, row);
This way you get a nullable object and all encountered exceptions force return null
You can use LINQ Cast operator instead of Select...
object[][] arr = result.Cast<object[]>().ToArray()
This is a little less verbose, but should be nearly identical performance wise. Another way is to do it manually:
object[][] arr = new object[result.Length][];
for (int i = 0; i < arr.Length; ++i)
arr[i] = (object[])result[i];
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
passing in object by ref
With the code below, the output would be:
Without:
With:1
Code:
static void Main(string[] args)
{
var listWithoutRef = new List<int>();
WithoutRef(listWithoutRef);
Console.WriteLine("Without:" + string.Join(" ", listWithoutRef));
var listWithRef = new List<int>();
WithRef(ref listWithRef);
Console.WriteLine("With:" + string.Join(" ", listWithRef));
}
static void WithoutRef(List<int> inList)
{
inList = new List<int>(new int[] { 1 });
}
static void WithRef(ref List<int> inList)
{
inList = new List<int>(new int[] { 1 });
}
By just looking at this, I would have said that a List is on the Heap, and so is passed by ref anyway, so they should be the same? Am I misunderstanding the ref keyword? Or am I missing something else?
Am I misunderstanding the ref keyword? Or am I missing something else?
Yes. You're not passing the list itself to the method, but rather passing the reference to the list by reference. This lets you change the reference (the List<int> that listWithRef actual refers to) within the method, and have it reflect.
Without using the ref keyword, your method can't change the reference to the list - the actual list storage mechanism is unchanged in either case.
Note that this isn't required if you just want to use the list. You can call List<int>.Add within either method, for example, and the list will get new items added to it. Ref is only required with reference types to change the reference itself.
Yes, all of the List objects are stored on the heap either way. However, without the ref keyword, you can't reassign the inList parameter and have it affect the caller's scope. When you create a new List object, it goes on the heap as a new object, but the original reference in the caller's scope is not affected unless you use the ref keyword.
In WithoutRef, if you call methods on the existing List without redefining it, you will see that it is modified:
inList.Clear();
inList.Add(1);
If I want an empty enumeration, I can call Enumerable.Empty<T>(). But what if I want to convert a scalar type to an enumeration?
Normally I'd write new List<string> {myString} to pass myString to a function that accepts IEnumerable<string>. Is there a more LINQ-y way?
You can use Repeat:
var justOne = Enumerable.Repeat(value, 1);
Or just an array of course:
var singleElementArray = new[] { value };
The array version is mutable of course, whereas Enumerable.Repeat isn't.
Perhaps the shortest form is
var sequence = new[] { value };
There is, but it's less efficient than using a List or Array:
// an enumeration containing only the number 13.
var oneIntEnumeration = Enumerable.Repeat(13, 1);
You can also write your own extension method:
public static class Extensions
{
public static IEnumerable<T> AsEnumerable<T>(this T item)
{
yield return item;
}
}
Now I haven't done that, and now that I know about Enumerable.Repeat, I probably never will (learn something new every day). But I have done this:
public static IEnumerable<T> MakeEnumerable<T>(params T[] items)
{
return items;
}
And this, of course, works if you call it with a single argument. But maybe there's something like this in the framework already, that I haven't discovered yet.
I have a lot of functions that look like this. Each has N arguments and each creates an SQLparamater array with each paramater being of this very similar form.
[WebMethod]
public static string accessServer(string dataField1, string dataField2, string dataField3) {
string value;
SQLParamater[] param = new SQLParameter[len] // len is the amount of arguments
param[0] = new SQLParameter("#dataField1", dataField1);
param[1] = new SQLParameter("#dataField2", dataField2);
param[2] = new SQLParameter("#dataField3", dataField3);
...
// do something with param
return value;
}
This looks like it can be done generically using a combination of Reflection and accessing the paramaters in a generic way.
Ideally a method of the form
public static SQLParamater[] getParams(someType paramaters)
and SQLParamater[] param = getParams(...)
I'm not sure how to pass on all the paramaters generically.
[Edit]
Note that the names of these datafields are important. It's not just an array of strings but rather a set of key/value pairs.
[/Edit]
You can use a function with variable arguments: name(params string[] arguments), so you can call, for example: name(arg1,arg2,arg3,arg4);
This has been asked about before (can't find that question though), the problem however is that while you can figure out the parameter names by using reflection MethodBase.GetCurrentMethod() you can't zip those names together with the parameter values because there's no way for you to access a parameter list of values.
There are other ways of trying to work around this very specific tiresome problem but I don't recommend doing it this way, it just doesn't make a lot of sense.
Now, given a method like this:
static void SomeMethod(string arg1, int arg2, object arg3)
{
}
You could do this:
static void Main()
{
var b = 123;
// this now becomes necessary as it's the only way of getting at the metadata
// in a presumable safe manner
Expression<Action> x = () => SomeMethod("a", b, "a" + b);
var args = GetArgs(x);
foreach (var item in args)
{
Console.WriteLine("{0}: {1}", item.Key, item.Value);
}
}
And implement the GetArgs method like so (you still need a way of putting those values somewhere becuase the invocation never occurs):
static IDictionary<string, object> GetArgs(Expression<Action> x)
{
var args = new Dictionary<string, object>();
var m = (MethodCallExpression)x.Body;
var parameters = m.Method.GetParameters();
for (int i = 0; i < m.Arguments.Count; i++)
{
// an easy way of getting at the value,
// no matter the complexity of the expression
args[parameters[i].Name] = Expression
.Lambda(m.Arguments[i])
.Compile()
.DynamicInvoke();
}
return args;
}
You infer the collection of name/value pairs from the expression tree created by the compiler, it's doable but kind of odd.
I think your API design is flawed if you need this, you would better have one method, which accepts a collection of some sort.
Code duplication like this is almost never the correct way to get things done.
EDIT
On topic:
I guess you can get the values from the stack: http://www.thescarms.com/dotnet/StackFrame.aspx
we do it like this:
var dict=new Dictionary
{
{"#param1",value1},
{"#param2",value2},
{"#param3",value3},
{"#param4",value4},
....
};
DALayer.ExecuteProc("procName",dict);
In the ExecuteProc function you can iterate over Dictionary object and set params using KeyValuePair object. But if you have to setup the datatype, lengths etc for the parameters then you have to do more work like preparing the sql command to query about parameters or passing more complicated object as parameter that contains information about datatype, length and direction etc.