Why array does not contain AsReadOnly method? - c#

List has instance method AsReadOnly:
var list = new List<int>();
var readOnlyList = list.AsReadOnly();
That creates ReadOnlyCollection:
public ReadOnlyCollection<T> AsReadOnly()
{
return new ReadOnlyCollection<T>((IList<T>) this);
}
But array has only static method for this:
var array = new int[] { };
var readOnlyArray = Array.AsReadOnly(array);
Doing the same:
public static ReadOnlyCollection<T> AsReadOnly<T>(T[] array)
{
if (array == null)
throw new ArgumentNullException(nameof (array));
return new ReadOnlyCollection<T>((IList<T>) array);
}
What the reason to declare different API for equal methods?

Array is an abstract class and was created before generics was a thing in .NET. If generics had always been a thing this class would almost certainly have been Array<T> rather than Array.
However, we can't go back and change a fundamental base class. As such, we cannot add an instance method to this class that is strongly typed to the specific type T of the array.
Hence, it's added as a static method instead.

This is just a long comment, not an answer to your question.
It is easy enough to create an extension method that gives you the syntax you want:
static class MyExtensions
{
public static ReadOnlyCollection<TEntry> AsReadOnly<TEntry>(this IList<TEntry> li)
=> new ReadOnlyCollection<TEntry>(li);
}
With that, you can do yourArray.AsReadOnly(). This has the benefit that it also works for all other types that happen to implement IList<>.
If you do not want that, of course you can extend only arrays:
static class MyExtensions
{
public static ReadOnlyCollection<TEntry> AsReadOnly<TEntry>(this TEntry[] arr)
=> Array.AsReadOnly(arr);
}
There is no reason to have both methods.

Array in it's nature is read only, i.e. you can't add an item to it and grow it. That is the reason we have no AsReadOnly method like IList.

Related

How can I create my personal ToList() function for static arrays

I must create ToDynamic() function for all types of static arrays,which returns a new dynamic list consisting of the elements of the array from which the function was called (just like ToList() works), like this:
int [] x = {1,2,3,4};
List<int> arr = x.ToDynamic();
You could just use x.ToList() to do what you want. If you really want to implement this yourself, you could just write a generic extension method like this:
public static class ArrayExtensions
{
public static List<T> ToDynamic<T>(this T[] items)
=> new List<T>(items ?? throw new ArgumentNullException(nameof(items)));
}
The scheme of extension methods writing is
// partial: often we have many extensions on collections (Tree, Aggregations etc.)
// which are implemented in different files
public static partial class EnumerableExtensions {
// IEnumerable<T> - choose argument's type being as much generic and basic as you can
public static List<T> ToDinamic<T>(this IEnumerable<T> source) {
// Validate argument(s)
if (null == source)
throw new ArgumentNullException(nameof(source)); // or return null or empty list
return new List<T>(source);
}
}

C# collection initializer – is it possible to add an element optionally, based on a condition?

Right now my code looks like this:
var ids = projectId.HasValue ? new List<Guid> { projectId.Value } : new List<Guid>();
Is there a more succinct way of creating a list in one line of code, with one element added optionally?
Another idea for an extension method (the name could definitely be improved, maybe PossiblyCreateSingletonList?):
public static class NullableExtensions
{
public static List<T> SingletonList<T>(this Nullable<T> item) where T : struct
{
return item.HasValue ? new List<T> { item.Value } : new List<T>();
}
}
Usage:
Guid? projectId = null;
List<Guid> projectIds = projectId.SingletonList(); // empty list
I would solve this using a extension method like this:
public static void AddIfNotNull<T>(this List<T> list, T? value) where T : struct
{
if(value != null)
{
list.Add(value.Value);
}
}
Than it could be used like this:
var ids = new List<Guid>();
ids.AddIfNotNull(projectId);
Maybe not as "crafty" (and not a one-liner) as your proposal, but in my opinion it is much easier to read and understand. If desired to be used as a one-liner you could modify the return type of the extension to be the list. That would make it possible to be used something like var ids = new List<Guid>().AddIfNotNull(projectId);
This probably isn't a good idea, but in C# 6, collection initializers also work when Add() is an extension method.
This means you can write the extension Add() like this:
public static void Add<T>(this List<T> list, T? item) where T : struct
{
if (item.HasValue)
{
list.Add(item.Value);
}
}
And then this code will do what you want:
var list = new List<Guid> { projectId };
Note that this will only work for value types (because of the T/T? distinction) and there is no simple way to make it work for reference types.
Also, I would find the line above very surprising, being more succinct is not always better. Which is why I actually wouldn't use this code.
That's pretty succinct, but another option would be to use LINQ:
var ids = new[] { projectId }.Where(x => x.HasValue).Select(x => x.Value).ToList();
If you're going the extension method route, it would have to look something like:
public static void AddIfNotNull<T>(this List<T> list, T? value)
where T : struct
{
if (value.HasValue)
{
list.Add(value.Value);
}
}
You'd have to build a second extension method for reference types (where T : class) if you needed.

How could I achieve JQuery style method calls on IEnumerables in C#?

In JQuery you can write $('.my-class').hide() and it will call hide() on all the results. There's no for loop, no iterating, no LINQ extensions and lambdas etc. and it makes dealing with lists super fun. I want to be able to have this functionality on IEnumerables in C#. I think Matlab has a similarly concise syntax when operating on arrays/matrices.
Long story short, I want the following code (or similar) to work:
class Program
{
static List<MyClass> MyList = new List<MyClass>();
static void Main(string[] args)
{
for (int i = 0; i < 100; i++)
MyList.Add(new MyClass());
MyList.MyMethod();
// should be exactly equivalent to:
MyList.Select(n => n.MyMethod());
}
}
class MyClass
{
public int MyMethod() { return 123; }
}
I'm aware this is possible on a case-by-case basis using extension methods:
public static IEnumerable<int> MyMethod(this IEnumerable<MyClass> lst)
{
return lst.Select(n => n.MyMethod());
}
But we'd have to create one extension method for every single method on every single type that you wanted this behaviour on.
Ideally this would be possible for all types and all methods and still be type-safe at compile time. I suspect I'm asking too much from the C# language here, but how would we do this or something similar in a as-generic-as-possible way?
Possible solutions:
Auto-generate extension methods for particular types. If we only intend to use this notation for a few types, we could just generate the extension methods once automatically. This would achieve the exact syntax and full type safety but generating code would be a pain.
A single extension method that returns a dynamic object built using reflection on the supplied type. The idea is that we'd use reflection to iterate through the type's methods and build up a dynamic object that would have all the methods like .MyMethod() that would behind the scenes call Select(...) on the IEnumerable. The syntax would end up being something like MyList.Selector().MyMethod(). But now we've lost the syntax and type safety. Clever, maybe. Useful, probably not.
Intercepting method calls? Is it possible to decide how to react to a method call at runtime? I don't know. Again you'd lose type safety.
The most simple solution is using dynamic objects. If you are willing to throw away type safety, you can make a IEnumerable type that behaves statically when needed and dynamically otherwise, here's a sample prototype:
public class DynamicIEnumerable<T> : DynamicObject, IEnumerable<T>
{
public IEnumerable<T> _enumerable;
public DynamicIEnumerable(IEnumerable<T> enumerable)
{
this._enumerable = enumerable;
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
result = new DynamicIEnumerable<T>(_enumerable.Select(x => (T)typeof(T).InvokeMember(binder.Name, BindingFlags.InvokeMethod, null, x, null)));
return true;
}
public IEnumerator<T> GetEnumerator()
{
return _enumerable.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return _enumerable.GetEnumerator();
}
}
In TryInvokeMember, the invoked member on IENumerable is applied on all items using reflection. The only constraints on this approach is that you have to return this in invoked method. Here's a sample of how to use this approach:
public class SomeClass
{
public int Value {get;set;}
public SomeClass(int value)
{
this.Value = x;
}
public SomeClass Plus10()
{
Value += 10;
return this;
}
}
static void Main()
{
dynamic d = new DynamicIEnumerable<X>(Enumerable.Range(0, 10).Select(x => new SomeClass(x)));
foreach (var res in d.Plus10().Plus10())
Console.WriteLine(res.Value);
}
how would we do this or something similar in a as-generic-as-possible way?
This isn't a pretty solution but it does work:
public class MyClass
{
public void MyMethod()
{
}
public void MyMethod2()
{
}
}
Extension Method:
public static class WeirdExtensions
{
public static IEnumerable<T> CallOnAll<T>(this IEnumerable<T> instance ,
Action<T> call)
{
foreach(var item in instance)
{
call(item);
}
return instance;
}
}
Usage (chaining/fluent):
var blah = new List<MyClass>();
blah.CallOnAll(b => b.MyMethod())
.CallOnAll(b => b.MyMethod2());
Notes
This isn't quite possible due to a the underlying assumption that you'd have to every single method on every single type. In jQuery/Html there is only one underlying type of an Html Element. All elements are exposed to the same methods (whether or not the type supports it). In jQuery, you can call $('head').hide() but it won't do anything visually, but because it is an element, it will be inline styled. If you need a new method, you do have a build one, but for only one type because there is only one type.
In contrast with C# you build your types (many many types) and they all have different methods (sure there could be overlap).

Using a class derived from generic list with LINQ

I have two classes, CheckboxItemsList which extends a generic list, and CheckboxItems, which contains a list of objects of type CheckboxItem.
I want to use LINQ to be able to filter CheckboxItemsList based on properties of its CheckboxItems objects. The return type is always a generic list, though, but I want it to be a CheckboxItemsList.
So I guess the basic question is, can linq be made to return a list of the same type that it starts with? Since I can't cast a base class to a derived class, do I have any option other than iterating through the results of the linq query and rebuilding the derived list object row by row? Not that this is the end of the world, but I'm relatively new to linq and was wondering it there is a better way to do it.
What I want:
CheckboxItemsList newList = MyCheckboxItemsList.Where(item=>item.Changed);
(obviously doesn't work since the query will return List<CheckboxItems>, not CheckboxItemsList)
The objects, generally:
public class CheckboxItemsList: List<CheckboxItems>
{
// does not add any fields, just access methods
}
public class CheckboxItems : IEnumerable<CheckboxItem>
{
public long PrimaryKey=0;
protected CheckboxItem[] InnerList;
public bool Changed
{
get {
return (InnerList.Any(item => item.Changed));
}
}
....
}
No, this is not possible out of the box. You'll need to add code to do this.
For example, you can add a constructor like so:
public CheckboxItemsList(IEnumerable<CheckboxItems> checkboxItems) {
// something happens
}
Then you can say
CheckboxItemsList newList = new CheckboxItemsList(
MyCheckboxItemsList.Where(item => item.Changed)
);
Additionally, you could add an extension method like so
static class IEnumerableCheckboxItemsExtensions {
public static ToCheckboxItemsList(
this IEnumerable<CheckboxItems> checkboxItems
) {
return new CheckboxItemsList(checkboxItems);
}
}
and then
CheckboxItemsList newList =
MyCheckboxItemsList.Where(item => item.Changed)
.ToCheckboxItemsList();
LINQ works on IEnumerable<T> and IQueryable<T> and the result types of all LINQ operations (Where, Select) etc, will return one of those. The standard ToList function returns a concrete list of type List<T>, you may need to come up with an extension method, e.g.:
public static CheckboxItemsList ToItemList(this IEnumerable<CheckboxItem> enumerable)
{
return new CheckboxItemsList(enumerable);
}
No, there's no built-in way to do this. You have two main options:
Add a constructor to your CheckboxItemsList class that takes an IEnumerable<CheckboxItems> or similar. Pass that collection on to the base List<T> constructor that takes an IEnumerable<T>. That base constructor should then populate the list for you:
var newList =
new CheckboxItemsList(MyCheckboxItemsList.Where(item=>item.Changed));
// ...
public class CheckboxItemsList : List<CheckboxItems>
{
public CheckboxItemsList(IEnumerable<CheckboxItems> collection)
: base(collection)
{
}
}
Create an extension method that takes an IEnumerable<CheckboxItems> or similar and returns a populated CheckboxItemsList:
var newList = MyCheckboxItemsList.Where(item=>item.Changed)
.ToCheckboxItemsList();
// ...
public static class EnumerableExtensions
{
public static CheckboxItemsList ToCheckboxItemsList(
this IEnumerable<CheckboxItems> source)
{
var list = new CheckboxItemsList();
foreach (T item in source)
{
list.Add(item);
}
return list;
}
}
(Of course, for completeness you could implement both of these options. The extension method would then just pass its IEnumerable<CheckboxItems> argument on to the constructor rather than manually looping and adding each item.)
You can also use "Conversion Operator", as below:
public class CheckboxItemsList: List<CheckboxItems>
{
public static implicit operator CheckboxItems(IEnumerable<CheckboxItems> items)
{
var list = new CheckboxItemsList();
foreach (var item in items)
{
list.Add(item);
}
return list;
}
}
Now, the below code would work.
CheckboxItemsList newList = MyCheckboxItemsList.Where(item=>item.Changed);
From MSDN:
A conversion operator declaration that includes the implicit keyword introduces a user-defined implicit conversion. Implicit conversions can occur in a variety of situations, including function member invocations, cast expressions, and assignments. This is described further in Section 6.1.
A conversion operator declaration that includes the explicit keyword introduces a user-defined explicit conversion. Explicit conversions can occur in cast expressions, and are described further in Section 6.2.
Here is what I came up with, building on the various suggestions of others. A generic extension method:
public static T ToList<T>(this IEnumerable baseList) where T : IList,new()
{
T newList = new T();
foreach (object obj in baseList)
{
newList.Add(obj);
}
return (newList);
}
So now I can do what I want:
CheckboxItemsList newList = MyCheckboxItemsList.Where(item=>item.Changed)
.ToList<CheckboxItemsList>();
Another pretty obvious solution occurred to me, which is also useful for situations where the derived list class has field properties that I need to maintain in the new list.
Just create a new instance of my derived list class, and use AddRange to populate it.
// When created with a CheckboxItemsList parameter, it creates a new empty
// list but copies fields
CheckboxItemsList newList = new CheckboxItemsList(OriginalList);
newList.AddRange(OriginalList.Where(item => item.Changed));

C# Generic overloading of List<T> : How would this be done?

The StringBuilder class allows you, in what I consider to be a very intuitive way, to chain method calls to .Append(), .AppendFormat() and some others like so:
StringBuilder sb = new StringBuilder();
sb.Append("first string")
.Append("second string);
The List class' .Add() method, on the other hand, returns void - so chaining calls doesn't work. This, in my opinion and the immortal words of Jayne Cobb "just don' make no kinda sense".
I admit that my understanding of Generics is very basic, but I would like to overload the .Add() method (and others) so that they return the original object, and allow chaining. Any and all assistance will be rewarded with further Firefly quotes.
If you want to keep the same name for the Add method, you could hide the method from the base class:
public class MyList<T> : List<T>
{
public new MyList<T> Add(T item)
{
base.Add(item);
return this;
}
}
However, this will only work if you're manipulating the list with a variable explicitly typed as MyList<T> (i.e. it won't work if your variable is declared as IList<T> for instance). So I think the solutions involving an extension method are better, even if that means changing the name of the method.
Although others have already posted solutions with extension methods, here's another one, that has the advantage of conserving the actual type of the collection:
public static class ExtensionMethods
{
public static TCollection Append<TCollection, TItem>(this TCollection collection, TItem item)
where TCollection : ICollection<TItem>
{
collection.Add(item);
return collection;
}
}
Use it like that:
var list = new List<string>();
list.Append("Hello").Append("World");
use can create extension method
public static class ListExtensions
{
public static List<T> AddItem<T>(this List<T> self, T item)
{
self.Add(item);
return self;
}
}
var l = new List<int>();
l.AddItem(1).AddItem(2);
EDIT
we can also make this method generic over collection parameter
public static class ListExtensions
{
public static TC AddItem<TC, T>(this TC self, T item)
where TC : ICollection<T>
{
self.Add(item);
return self;
}
}
var c1 = new Collection<int>();
c1.AddItem(1).AddItem(2);
var c2 = new List<int>();
c2.AddItem(10).AddItem(20);
EDIT 2:
Maybe someone will find this trick useful, it is possible to utilize nested object initializer and collection initializer for setting properties and adding values into existing instances.
using System;
using System.Collections.Generic;
using System.Linq;
struct I<T>
{
public readonly T V;
public I(T v)
{
V = v;
}
}
class Obj
{
public int A { get; set; }
public string B { get; set; }
public override string ToString()
{
return string.Format("A={0}, B={1}", A, B);
}
}
class Program
{
static void Main()
{
var list = new List<int> { 100 };
new I<List<int>>(list)
{
V = { 1, 2, 3, 4, 5, 6 }
};
Console.WriteLine(string.Join(" ", list.Select(x => x.ToString()).ToArray())); // 100 1 2 3 4 5 6
var obj = new Obj { A = 10, B = "!!!" };
Console.WriteLine(obj); // A=10, B=!!!
new I<Obj>(obj)
{
V = { B = "Changed!" }
};
Console.WriteLine(obj); // A=10, B=Changed!
}
}
public static IList<T> Anything-not-Add*<T>(this IList<T> list, T item)
{
list.Add(item);
return list;
}
* AddItem, Append, AppendList, etc. (see comments below)
The same idea came to my mind like other guys' too, independently:
public static TList Anything<TList, TItem>(this TList list, TItem item)
where TList : IList<TItem>
{
list.Add(item);
return list;
}
And Thomas is right: as far as IList<T> inherits ICollection<T> you should use ICollection.
Have an extension method off:
public static List<T> Append(this List<T> list, T item)
{
list.Add(item);
return self;
}
Note that we have to create it with a new name, as if an instance member matches the signature (the 'Add' you are already complaining about) then the extension method won't be called.
In all though, I'd recommend against this. While I like chaining myself, it's being rare in C# libraries means it's not as idiomatic as it is in other languages where it's more common (no technical reason for this, though some differences in how properties work encourages it a bit more in some other languages, just the way things are in terms of what is common). Because of this, the constructs it enables aren't as familiar in C# as elsewhere, and your code is more likely to be misread by another dev.
You could use an extension method with a different name:
public static T Put<T, U>(this T collection, U item) where T : ICollection<U> {
collection.Add(item);
return collection;
}
To create code like this:
var list = new List<int>();
list.Put(1).Put(2).Put(3);
To retain the name Add, however, you can have a method like this:
public static T Add<T, U>(this T collection, Func<U> itemProducer)
where T : ICollection<U> {
collection.Add(itemProducer());
return collection;
}
And create code like this:
list.Add(()=>1).Add(()=>2).Add(()=>3);
It doesn't look that good though.
Maybe if we change the type we can have a better syntax.
Given this class:
public class ListBuilder<T> {
IList<T> _list;
public ListBuilder(IList<T> list) {
_list = list;
}
public ListBuilder<T> Add(T item) {
_list.Add(item);
return this;
}
}
You can have this method:
public static ListBuilder<T> Edit<T>(this IList<T> list) {
return new ListBuilder<T>(list);
}
And use code like this:
list.Edit().Add(1).Add(2).Add(3);
I'm sure you won't appreciate this answer but there's a very good reason that List<>.Add() works this way. It is very fast, it needs to be to be competitive with an array and because it is such a low-level method. It is however just a hair too big to get inlined by the JIT optimizer. It cannot optimize the return statement you'd need to return the list reference.
Writing lst.Add(obj) in your code is for free, the lst reference is available in a CPU register.
A version of Add() that returns the reference makes the code almost 5% slower. It's a lot worse for the proposed extension method, there an entire extra stack frame involved.
I like the extension approach that others have mentioned as that seems to answer the question well (although you would have to give it a different method signature than the existing Add()). Also, it does seem like there's some inconsistency about object returns on calls like this (I thought it was a mutability issue, but the stringbuilder is mutable isn't it?), so you raise an interesting question.
I'm curious, though, if the AddRange method would not work as an out-of-the-box solution? Is there a particular reason you want to chain the commands instead of passing everything in as a an array?
Would do something like this not accomplish what you need?
List<string> list = new List<string>();
list.AddRange(new string[]{
"first string",
"second string",
});

Categories

Resources