My array class in C# - c#

I'm trying to do this with Dictionary, Array seems more general so I'm using it as an example.
Class MyArray
{
private Array array;
public Array [p] // a property
{
get {return array[p]};
set
{
array[p] = value;
more_stuff();
}
}
}
This is sudo-code. I've included only a part of the class, where my problem would be. Can I use a property as above, or another structure to achieve this?
(new MyArray[]{4, 3, 1, 5})[2] = 4;

You're looking for an indexer.
So you're class should look like this:
class MyArray<T>
{
private T[] array = new T[100];
public T this[int p]
{
get
{
return array[p];
}
set
{
array[p] = value;
// more_stuff();
}
}
}
To be able to use a collection initializer (e.g. new MyArray<int>{4, 3, 1, 5}), your class has to implement IEnumerable and provide a Add method.

Related

Is it possible to make a variable that can be an array or a non-array?

I want to be able to do something like
public string[]|string stringsOrSingleString;
I want to create a variable that can be an array or a non-array of a specific type (a string in the example).
Example usage
I want to be able to do stringsOrSingleString = "bla" or stringsOrSingleString = new string[] { "bla" };
Do I need a custom class to do this? Preferably, I don't want to use a custom class, but if necessary then ok.
I should be able to tell later on if the value assigned was an array or non-array, using typeof or is, or something.
The whole reason for this ordeal is that I have a javascript API(that I didn't create), and I am trying to make a C# api that follows the JS api/syntax as close as possible.
Is this possible?
May be you want something like this?
public class Item<T>
{
public T Value => this.Values.Length > 0 ? this.Values[0] : default(T);
public T[] Values { get; set; }
}
The class has an array of values and a single value. There are some implementations like this, for example, when you select files with OpenFileDialog: you have a list of files (for MultiSelect case) and also a single SelectedFile. My answer is focused with this in mind. If you need another thing, give more information.
UPDATE
You can update previous class in this way:
public class Item<T>
{
public T Value => this.Values.Length > 0 ? this.Values[0] : default(T);
public T[] Values { get; set; }
public T this[int index] => this.Values[index];
public static implicit operator Item<T>(T value)
{
return new Item<T> { Values = new[] { value } };
}
public static implicit operator Item<T>(List<T> values)
{
return new Item<T> { Values = values.ToArray() };
}
public static implicit operator Item<T>(T[] values)
{
return new Item<T> { Values = values };
}
}
Example usage:
Item<string> item = "Item1";
string text = item.Value;
string sameText = item[0];
Item<string> items = new[] { "Item1", "Item2" };
string[] texts = item.Values;
string item1 = item[0];
string item2 = item[1];
You can create an instance using a simple object or an array. You can access to the first value using Value property and to all items using Values. Or use the indexer property to access to any item.
In C# you need to know the type of the variable. It's difficult work in the same form of JavaScript. They are very different languages.

Initializing an array of generic collections with each a different generic argument

During the development of one of my projects, I encountered an issue regarding generic types.
The project requires me to write a class that would act as a source of list objects. Suppose I had the following class:
public class TablesProvider
{
private readonly List[] _tables;
public TablesProvider()
{
// initialize the tables var here....
}
public List<TItem> GetTable<TItem>()
{
return (List<TItem>)_tables.Single(x => x is List<TItem>);
}
}
This class obviously doesn't work, because the List type is a generic type and therefore the generic arguments should be specified.
So I made an abstract type called MyList, that would be derived by a more specific type MyList<TItem> in order to escape this requirement, and edited the TablesProvider a little.
public class TablesProvider
{
private readonly MyList[] _tables;
public TablesProvider()
{
// initialize the tables var here....
}
public MyList<TItem> GetTable<TItem>()
{
return (MyList<TItem>)_tables.Single(x => x is MyList<TItem>);
}
}
public abstract class MyList
{
// ...
}
public class MyList<TItem> : MyList, IList<TItem>
{
private readonly List<TItem> _elements = new List<TItem>();
public TItem this[int index]
{
get { return _elements[index]; }
set { _elements[index] = value; }
}
// ...
}
This works quite well. There is only one problem left. Suppose I had 45 different collections, each defined with a different generic argument. What would be the best way of initializing all of those collections? I cannot use a for loop here, since generic parameters are specified at compile-time and not at runtime, and therefore a construction like this wouldn't be possible:
for (int i = 0; i < 45; i++)
_tables[i] = new MyList<GenericParameters[i]>();
My ultimate goal is to have the luxury to just do something like this...
var table = _tablesProvider.GetTable<SomeClass>();
var element = table[3];
var propertyValue = element.SomeProperty;
... without the need to cast the variable element in order to access its type-specific members.
It is probably worth mentioning that the amount of different list objects is fixed to 45. This will not change. In theory, I could initialize the array line by line, or have 45 properties or variables instead. Both of these options, however, sound as a rather cheap solution to me, but I will accept one of them if there is no other way.
Any of you got some ideas? Am I doing this completely wrong? Should I consider an other structure?
Thanks in advance.
Yes, it is possible to do what you are describing if you use reflection.
Supposing that your hypothetical GenericParameters array is an array of Types (since you can't have an array of type identifiers), you can define this helper function:
private MyList MakeList(Type t)
{
return (MyList)Activator.CreateInstance(typeof(MyList<>).MakeGenericType(t));
}
And that will allow you to do this:
public TablesProvider()
{
var GenericParameters = new[] { typeof(string), typeof(int), typeof(DateTime) };
_tables = new MyList[GenericParameters.Length];
for (int i = 0; i < GenericParameters.Length; i++)
{
_tables[i] = MakeList(GenericParameters[i]);
}
}
You can even use LINQ if you want:
public TablesProvider()
{
var GenericParameters = new[] { typeof(string), typeof(int), typeof(DateTime) };
_tables = GenericParameters.Select(MakeList).ToArray();
}
Previous answer:
Well, the reality is that you're going to have a list of 45 different types somewhere, which pretty much means you're going to have 45 different lines of similar code. So one could say the goal is to make those lines as concise as possible.
One way to do so would be to add a helper function:
private void AddTable<T>()
{
_tables.Add(new MyTable<T>());
}
(this assumes changing _tables to a List<MyTable>)
Then you could just do:
AddTable<Type1>();
AddTable<Type2>();
AddTable<Type3>();
AddTable<Type4>();
this implementation works
public class TablesProvider
{
private readonly List<object> _tables;
public TablesProvider()
{
_tables = new List<object>();
}
public IList<TItem> GetTable<TItem>()
{
var lst = (List<TItem>)_tables.SingleOrDefault(x => x is List<TItem>);
if (lst == null)
{
lst = new List<TItem>();
_tables.Add(lst);
}
return lst;
}
}
it creates List of TItem when necessary; next time it returns the same list for TItem. it is lazy initialization
so you can do invoke
var table = _tablesProvider.GetTable<SomeClass>();
without any code like this:
for (int i = 0; i < 45; i++)
_tables[i] = new MyList<GenericParameters[i]>();
it is not ThreadSafe

Unified way to access arrays with different types

Supposing I have the following classes:
class Master {
int x;
int y;
public int X { get { return x; } set { x = value; } }
public int Y { get { return y; } set { y = value; } }
}
class Sub1:Master {
int z;
public int Z { get { return z; } set { z = value; } }
}
class Sub2:Master {
int w;
public int W { get { return w; } set { w = value; } }
}
class Sub3:Master {
int t;
public int T { get { return t; } set { t = value; } }
}
Then I have defined three different arrays, one for each Sub* type:
List<Sub1> array1;
List<Sub2> array2;
List<Sub3> array3;
And finally I need a way to access all instances in a unified way. The idea was to use a new array List<T>[] array4 = new[] {array1, array2, array3}; and use an int as index, so I don't have to write three times the common operations for properties X and Y.
However, I can't do it in this way because the three arrays have different type. What can I use?
They share a base type so you can create a List<Master> to hold instances of all three types.
Ultimately, all objects share the same base type object so it always possible to have a List<object>, but in this case they share a base type higher in the hierarchy so you can use Master.
To create a list for all the instances you can do something like this:
var all = new List<Master>(array1.Count + array2.Count + array3.Count);
all.AddRange(array1);
all.AddRange(array2);
all.AddRange(array3);
First you create a new list and since you already know what the expected capacity should be you use the constructor overload that accepts an int capacity. This way the list does not have to be resized when you add the other collections, which leads to more efficient code.
As a side note and I know this is probably only sample code but nonetheless you should name your variables according to what they represent, so naming something like array* should be reserved for when they really represent arrays.
List implements the non-generic interfaces ICollection, IEnumerable and IList, so you can create a new array of IList[] array4 = { array1, array2, array3 };
Or, while adding elements at your Lists you could add them (also) to another list of type Master, like this
List<Sub1> array1 = new List<Sub1>();
List<Sub2> array2 = new List<Sub2>();
List<Sub3> array3 = new List<Sub3>();
List<Master> array4 = new List<Master>();
...
public void AddSub1(Sub1 sub)
{
array1.Add(sub);
array4.Add(sub);
}
public void AddSub2(Sub2 sub)
{
array2.Add(sub);
array4.Add(sub);
}
public void AddSub3(Sub3 sub)
{
array3.Add(sub);
array4.Add(sub);
}
This way, you can iterate over all elements of array4:
foreach(Master master in array4)
{
master.DoSomething();
}
You can actually make this work by using the fact that IEnumerable<T> is declared as IEnumerable<out T>, and that Enumerable.ElementAt<T> is optimized for the runtime type of the IEnumerable<T> implementing IList<T>. That lets you do this:
var x = new IEnumerable<Master>[] {array1, array2, array3};
x[0].ElementAt(4);
While still getting constant-time access to the individual elements of the lists. It feels a little clunky, but should still work.
If it fits the work being done, a better option in my opinion would be to create a generic method, and call the generic method on each of your lists:
private void MainMethod()
{
List<Sub1> array1 = new List<Sub1>();
List<Sub2> array2 = new List<Sub2>();
List<Sub3> array3 = new List<Sub3>();
DoOperation(array1);
DoOperation(array2);
DoOperation(array3);
}
private void DoOperation<T>(List<T> list) where T: Master
{
// do work here
list[0].X = 0;
}

Using Property to get array element in C#

Is there a way to get a specific element (based in index) from a string array using Property. I prefer using public property in place of making the string array public. I am working on C#.NET 2.0
Regards
Are you possibly trying to protect the original array; do you mean you want a protective wrapper around the array, through "a Property" (not of its own)? I'm taking this shot at guessing the details of your question. Here's a wrapper implementation for a string array. The array cannot be directly access, but only through the wrapper's indexer.
using System;
public class ArrayWrapper {
private string[] _arr;
public ArrayWrapper(string[] arr) { //ctor
_arr = arr;
}
public string this[int i] { //indexer - read only
get {
return _arr[i];
}
}
}
// SAMPLE of using the wrapper
static class Sample_Caller_Code {
static void Main() {
ArrayWrapper wrapper = new ArrayWrapper(new[] { "this", "is", "a", "test" });
string strValue = wrapper[2]; // "a"
Console.Write(strValue);
}
}
If I understand correctly what you are asking, You can use an indexer.
Indexers (C# Programming Guide)
Edit: Now that I've read the others, maybe you can expose a property that returns a copy of the array?
If the property exposes the array:
string s = obj.ArrayProp[index];
If you mean "can I have an indexed property", then no - but you can have a property that is a type with an indexer:
static class Program
{
static void Main()
{
string s = ViaArray.SomeProp[1];
string t = ViaIndexer.SomeProp[1];
}
}
static class ViaArray
{
private static readonly string[] arr = { "abc", "def" };
public static string[] SomeProp { get { return arr; } }
}
static class ViaIndexer
{
private static readonly IndexedType obj = new IndexedType();
public static IndexedType SomeProp { get { return obj; } }
}
class IndexedType
{
private static readonly string[] arr = { "abc", "def" };
public string this[int index]
{
get { return arr[index]; }
}
}
What you need is a Property that can have input (an index).
There is only one property like that, called an Indexer.
Look it up on MSDN.
A shortcut: use a built in code snippet: go to your class and type 'indexer' then press tab twice. Viola!
Properties don't take parameters, so that won't be possible.
You can build a method, for instance
public string GetStringFromIndex(int i)
{
return myStringArray[i];
}
Of course you'll probably want to do some checking in the method, but you get the idea.
I'm assuming that you have a class that has a private string array and you want to be able to get at an element of the array as a property of your class.
public class Foo
{
private string[] bar;
public string FooBar
{
get { return bar.Length > 4 ? bar[4] : null; }
}
}
This seems horribly hacky, though, so I'm either not understanding what you want or there's probably a better way to do what you want, but we'd need to know more information.
Update: If you have the index of the element from somewhere else as you indicate in your comment, you could use an indexer or simply create a method that takes the index and returns the value. I'd reserve the indexer for a class that is itself a container and use the method route otherwise.
public string GetBar( int index )
{
return bar.Length > index ? bar[index] : null;
}
Just return the array from the property; the resulting object will behave as an array, so you can index it.
E.G.:
string s = object.Names[15]
What you're asking can be done, like so:
You can initialize an object that holds your array, giving you exactly what you need:
public class ArrayIndexer<T> {
private T[] myArrRef;
public ArrayIndexer(ref T[] arrRef) {
myArrRef = arrRef;
}
public T this [int index] {
get { return myArrRef[index]; }
}
}
Then, in your class:
public ArrayIndexer arr;
private SomeType[] _arr;
//Constructor:
public MyClass(){
arr = new ArrayIndexer<SomeType>(ref _arr);
}
Usage:
myClassObj.arr[2] // Gives the second item in the array.
Et Voila! An indexed property.

Is there any way to use an extension method in an object initializer block in C#

The simple demo below captures what I am trying to do. In the real program, I have to use the object initialiser block since it is reading a list in a LINQ to SQL select expression, and there is a value that that I want to read off the database and store on the object, but the object doesn't have a simple property that I can set for that value. Instead it has an XML data store.
It looks like I can't call an extension method in the object initialiser block, and that I can't attach a property using extension methods.
So am I out of luck with this approach? The only alternative seems to be to persuade the owner of the base class to modify it for this scenario.
I have an existing solution where I subclass BaseDataObject, but this has problems too that don't show up in this simple example. The objects are persisted and restored as BaseDataObject - the casts and tests would get complex.
public class BaseDataObject
{
// internal data store
private Dictionary<string, object> attachedData = new Dictionary<string, object>();
public void SetData(string key, object value)
{
attachedData[key] = value;
}
public object GetData(string key)
{
return attachedData[key];
}
public int SomeValue { get; set; }
public int SomeOtherValue { get; set; }
}
public static class Extensions
{
public static void SetBarValue(this BaseDataObject dataObject,
int barValue)
{
/// Cannot attach a property to BaseDataObject?
dataObject.SetData("bar", barValue);
}
}
public class TestDemo
{
public void CreateTest()
{
// this works
BaseDataObject test1 = new BaseDataObject
{ SomeValue = 3, SomeOtherValue = 4 };
// this does not work - it does not compile
// cannot use extension method in the initialiser block
// cannot make an exension property
BaseDataObject test2 = new BaseDataObject { SomeValue = 3, SomeOtherValue = 4, SetBarValue(5) };
}
}
One of the answers (from mattlant) suggests using a fluent interface style extension method. e.g.:
// fluent interface style
public static BaseDataObject SetBarValueWithReturn(this BaseDataObject dataObject, int barValue)
{
dataObject.SetData("bar", barValue);
return dataObject;
}
// this works
BaseDataObject test3 = (new BaseDataObject { SomeValue = 3, SomeOtherValue = 4 }).SetBarValueWithReturn(5);
But will this work in a LINQ query?
Object Initializers are just syntactic sugar that requires a clever compiler, and as of the current implementation you can't call methods in the initializer.
var x = new BaseDataObject { SomeValue = 3, SomeOtherValue = 4 };
Will get compiler to something like this:
BaseDataObject tempObject = new BaseDataObject();
tempObject.SomeValue = 3;
tempObject.SomeOtherValue = 4;
BaseDataObject x = tempObject;
The difference is that there can't be any synchronization issues. The variable x get's assigned the fully assigned BaseDataObject at once, you can't mess with the object during it's initialization.
You could just call the extension method after the object creation:
var x = new BaseDataObject { SomeValue = 3, SomeOtherValue = 4 };
x.SetBarValue()
You could change SetBarValue to be a property with get/set that can be assigned during initialization:
public int BarValue
{
set
{
//Value should be ignored
}
}
Or, you could subclass / use the facade pattern to add the method onto your object:
public class DataObjectWithBarValue : BaseDataObject
{
public void BarValue
{
set
{
SetData("bar", value);
}
get
{
(int) GetData("bar");
}
}
}
No but you could do this....:
BaseDataObject test2 = (new BaseDataObject { SomeValue = 3, SomeOtherValue = 4}).SetBarValue(5);
ANd have your extension return the object like Linq Does.
EDIT: This was a good thought untill i reread and saw that the base class was developed by a third person: aka you dont have the code. Others here have posted a correct solution.
Even better:
public static T SetBarValue<T>(this T dataObject, int barValue)
where T : BaseDataObject
{
dataObject.SetData("bar", barValue);
return dataObject;
}
and you can use this extension method for derived types of BaseDataObject to chain methods without casts and preserve the real type when inferred into a var field or anonymous type.
static T WithBarValue<T>(this T dataObject, int barValue)
where T : BaseDataObject
{ dataObject.SetData("bar", barValue);
return dataObject;
}
var x = new BaseDataObject{SomeValue=3, OtherValue=4}.WithBarValue(5);
Is extending the class a possibility? Then you could easily add the property you need.
Failing that, you can create a new class that has similar properties that simply call back to a private instance of the class you are interested in.
Right, having learned from the answerers, the short answer to "Is there any way to use an extension method in an object initializer block in C#?" is "No."
The way that I eventually solved the problem that I faced (similar, but more complex that the toy problem that I posed here) was a hybrid approach, as follows:
I created a subclass, e.g.
public class SubClassedDataObject : BaseDataObject
{
public int Bar
{
get { return (int)GetData("bar"); }
set { SetData("bar", value); }
}
}
Which works fine in LINQ, the initialisation block looking like
SubClassedDataObject testSub = new SubClassedDataObject
{ SomeValue = 3, SomeOtherValue = 4, Bar = 5 };
But the reason that I didn't like this approach in the first place is that these objects are put into XML and come back out as BaseDataObject, and casting back was going to be an annoyance, an unnecessary data copy, and would put two copies of the same object in play.
In the rest of the code, I ignored the subclasses and used extension methods:
public static void SetBar(this BaseDataObject dataObject, int barValue)
{
dataObject.SetData("bar", barValue);
}
public static int GetBar(this BaseDataObject dataObject)
{
return (int)dataObject.GetData("bar");
}
And it works nicely.

Categories

Resources