Restrict an IList<T> extension method to exclude Arrays - c#

Supposing I create an extension method for IList but this extension is part of a library potentially used across many projects. I do not have the control on how it is called.
Is there a way to prevent an Array to call an IList<T> extension method at compile time? This to avoid any misuse, the caller cannot guess the exact implementation, if the .Add() method would be called or only the indexer for example.
I could not find a possible solution with generic constraint type.
So far the only possibility left would be to restrict the extension method to List<T> directly.
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
var array = new[]{"Hello"};
array.DummyInsert("World"); // this will crash at run time
}
}
public static class DummyExtension
{
public static T DummyInsert<T>(this IList<T> list, T insertValue)
{
list.Add(insertValue);
return insertValue;
}
}

You can add your extension method to List<T> not on IList<T>

I Agree with Ed Plunkett, use a ReadOnlyCollection<T>. But you can do it like this. It's your foot, you can shoot it if you want.
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
var array = new[]{"Hello"};
var world = array.Insert("World"); // this will crash at run time
Console.WriteLine(array.Length);
}
}
public static class DummyExtension
{
public static T Insert<T>(this IList<T> list, T insertValue)
{
Console.WriteLine("WrongInsert");
list.Add(insertValue);
return insertValue;
}
[Obsolete("If want a compile time exception you can do this too.", true)]
public static T Insert<T>(this T[] list, T insertValue)
{
Console.WriteLine("RightInsert");
return insertValue;
}
}
This prints
RightInsert
1
https://dotnetfiddle.net/i6p1Z5
EDIT:
It was pointed out in the comments below that this won't work if your array has been cast to an IList<T> either explicitly or implicitly. There is nothing wrong with using List<T> here instead of IList<T> unless you are trying to actually extend the IList<T>. In that case extend it in a way that makes sense for all IList<T>. I just wanted to show that yes, what you ask can be done. With great power comes great responsibility.

The run-time issue is because of the fact that the Array is of fixed length hence when you try to insert an element into it you end up with an exception. Instead you can have your own extension method for case Array and handle the insertion accordingly.
public class Program
{
public static void Main()
{
var array = new[] { "Hello" };
array = array.Insert("World");
}
}
public static class DummyExtension
{
public static T Insert<T>(this IList<T> list, T insertValue)
{
list.Add(insertValue);
return insertValue;
}
public static T[] Insert<T>(this T[] list, T insertValue)
{
var destArray = new T[list.Length + 1];
Array.Copy(list, destArray, list.Length);
destArray[destArray.Length - 1] = insertValue;
return destArray;
}
}
Well I agree it may be a crude way, but it will work for your case.

Related

What is the "type" of a generic IList<T>?

Imagine an extension like this..
public static Blah<T>(this IList<T> ra)
{
..
}
Imagine you want to make a note of the most recently-called one.
private static IList recent;
public static Blah<T>(this IList<T> ra)
{
recent = ra;
..
}
You actually can not do that:
error CS0266: Cannot implicitly convert type System.Collections.Generic.IList<T> to System.Collections.IList.
1- You can simply make recent an object and that seems to work fine, but it seems like a poor solution.
2- It seems if you do have recent as an IList, you can actually cast the "ra" to that...
recent = (System.Collections.IList)ra;
and it seems to work. Seems strange though?? So,
3- Actually, what type should recent be so that you don't have to cast to it?? How can you make recent the same type as ra? You can't say this ....
private static System.Collections.Generic.IList recent;
it's not meaningful. So what the heck is the type of "ra"? What should recent "be" so that you can simply say recent=ra ?
(I mention this is for Unity, since you constantly use generic extensions in Unity.)
4- Consider a a further difficulty the case if you want to have a Dictionary of them all.
private static Dictionary<object,int> recents = new Dictionary<object,int>();
I can really only see how to do it as an object.
USE CASE EXAMPLE.
Here's an extension you use constantly, everywhere, in game engineering,
public static T AnyOne<T>(this IList<T> ra)
{
int k = ra.Count;
if (k<=0) {Debug.Log("Warn!"+k);}
int r = UnityEngine.Random.Range(0,k);
return ra[r];
}
no problem so far. So,
explosions.AnyOne();
yetAnotherEnemyToDefeat = dinosaurStyles.AnyOne();
and so on. However. Of course, actual random selections feel bad; in practice what you want is a fairly non-repeating order, more like a shuffle. Usually the best thing to do with any list or array is shuffle them, and serve them in that order; perhaps shuffle again each time through. Simple example, you have 20 random sound effects roars , being for when the dino roars. Each time you need one, if you do this
roars.AnyOne();
its OK, but not great. It will sound sort of suck. (Most players will report it as "not being random" or "repeating a lot".) This
roars.NextOne();
is much better. So, NextOne() should, on its own, (a) if we're at the start shuffle the list, (b) serve it in that order, (c) perhaps shuffle it again each time you use up the list. {There are further subtleties, eg, try not to repeat any near the end/start of the reshuffle, but irrelevant here.}
Note that subclassing List (and/or array) would suck for many obvious reasons, it's a job for a simple self-contained extension.
So then, here's a beautiful way to implement NextOne() using a simple stateful extension.
private static Dictionary<object,int> nextOne = new Dictionary<object,int>();
public static T NextOne<T>(this IList<T> ra)
{
if ( ! nextOne.ContainsKey(ra) )
// i.e., we've never heard about this "ra" before
nextOne.Add(ra,0);
int index = nextOne[ra];
// time to shuffle?
if (index==0)
{
Debug.Log("shuffling!"); // be careful to mutate, don't change the ra!
IList<T> temp = ra.OrderBy(r => UnityEngine.Random.value).ToList();
ra.Clear(); foreach(T t in temp) ra.Add(t);
}
T result = ra[index];
++index;
index=index%ra.Count;
nextOne[ra] = index;
return result;
}
This is surely the perfect example of a "stateful extension".
Notice indeed, I just used "object".
I guess in a way, the fundamental question in this QA is, is it best to use the Dictionary of "object" there, or, would something else more typey be better? Really that's the question at hand. Cheers!
If you want a single globally most recent IList<T> where T potentially varies each time, then your only options are to use object or dynamic. Both require casting; the latter just casts automatically.
I think your confusion stems from thinking that IList<T> inherits IList - it doesn't:
public interface IList<T> : ICollection<T>, IEnumerable<T>, IEnumerable
So arguably you could do this, although I don't see any advantage really:
private static IEnumerable recent;
public static void Blah<T>(this IList<T> ra)
{
recent = ra;
...
}
The simplest, and most type-safe, solution is to store a separate value for each T:
private static class RecentHolder<T> {
public static IList<T> Value { get; set; }
}
public static Blah<T>(this IList<T> ra) {
RecentHolder<T>.Value = ra;
}
What is the “type” of a generic IList< T >?
The base type..
Console.WriteLine( new List<int>().GetType().BaseType);
System.Object
The Generic Type definition ...
Console.WriteLine( new List<int>().GetType().GetGenericTypeDefinition());
System.Collections.Generic.List`1[T]
And to expand on SLAKS Answer
Not really. In the absence of a separate common non-generic base class
You can also use interfaces. So you could do...
public interface IName
{
string Name { get; set; }
}
public class Person : IName
{
public string Name { get; set; }
}
public class Dog : IName
{
public string Name { get; set; }
}
Then you could
private static List<IName> recent;
public static Blah<T>(this List<IName> ra)
{
recent = ra;
..
}
and it won't matter if you put Dog or Person in the list.
OR
I can't believe I didn't think about this last night; LINQ to the rescue using object.
using System;
using System.Linq;
using System.Collections.Generic;
public class Program
{
private static class WonkyCache
{
private static List<object> cache = new List<object>();
public static void Add(object myItem)
{
cache.Add(myItem);
}
public static IEnumerable<T> Get<T>()
{
var result = cache.OfType<T>().ToList();
return result;
}
}
public static void Main()
{
WonkyCache.Add(1);
WonkyCache.Add(2);
WonkyCache.Add(3);
WonkyCache.Add(Guid.NewGuid());
WonkyCache.Add("George");
WonkyCache.Add("Abraham");
var numbers = WonkyCache.Get<int>();
Console.WriteLine(numbers.GetType());
foreach(var number in numbers)
{
Console.WriteLine(number);
}
var strings = WonkyCache.Get<string>();
Console.WriteLine(strings.GetType());
foreach(var s in strings)
{
Console.WriteLine(s);
}
}
}
Results:
System.Collections.Generic.List`1[System.Int32]
1
2
3
System.Collections.Generic.List`1[System.String]
George
Abraham
Try:
public static class StatefulRandomizer<T>
// Use IEquatable<T> for Intersect()
where T : IEquatable<T>
{
// this could be enhanced to be a percentage
// of elements instead of hardcoded
private static Stack<T> _memory = new Stack<T>();
private static IEnumerable<T> _cache;
public static void UpdateWith(IEnumerable<T> newCache)
{
_cache = newCache.ToList();
// Setup the stack again, keep only ones that match
var matching = _memory.Intersect(newCache);
_memory = new Stack<T>(matching);
}
public static T GetNextNonRepeatingRandom()
{
var nonrepeaters = _cache
.Except(_memory);
// Not familar with unity.. but this should make
// sense what I am doing
var next = nonrepeaters.ElementAt(UnityEngine.Random(0, nonrepeaters.Count()-1));
// this fast, Stack will know it's count so no GetEnumerator()
// and _cache List is the same (Count() will call List.Count)
if (_memory.Count > _cache.Count() / 2)
{
_memory.Pop();
}
_memory.Push(next);
return next;
}
}

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).

Extension Method to Get the Values of Any Enum

I've been trying to create an extension method, that would work on any enum, to return its values.
Instead of doing this:
Enum.GetValues(typeof(BiasCode)).Cast<BiasCode>()
It would be nice to do this:
new BiasCode().Values()
It would even be better without new, but that's another issue.
I have a .NET fiddle that has a solution that's close (code shown below). The problem with this code is that the extension method is returning List<int>. I would like to have it return a list of the enum values itself. Returning List<int> isn't terrible; it just means I have to cast the result.
Is it even possible to do this? I tried making the extension method generic, but ran into problems. This is as close as I was able to get:
using System;
using System.Linq;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
foreach (int biasCode in new BiasCode().Values())
{
DisplayEnum((BiasCode)biasCode);
}
}
public static void DisplayEnum(BiasCode biasCode)
{
Console.WriteLine(biasCode);
}
}
public enum BiasCode
{
Unknown,
OC,
MPP
}
public static class EnumExtensions
{
public static List<int> Values(this Enum theEnum)
{
var enumValues = new List<int>();
foreach (int enumValue in Enum.GetValues(theEnum.GetType()))
{
enumValues.Add(enumValue);
}
return enumValues;
}
}
You can return an instance of the appropriate enum type (created using reflection), but its static type cannot be List<EnumType>. That would require EnumType to be a generic type parameter of the method, but then the type would have to be constrained to only enum types and that is not possible in C#.
However, you can get close enough in practice (and add runtime checks to top it off) so you can write a method that works like this:
public static IEnumerable<TEnum> Values<TEnum>()
where TEnum : struct, IComparable, IFormattable, IConvertible
{
var enumType = typeof(TEnum);
// Optional runtime check for completeness
if(!enumType.IsEnum)
{
throw new ArgumentException();
}
return Enum.GetValues(enumType).Cast<TEnum>();
}
which you can invoke with
var values = Values<BiasCode>();
I have made the method return IEnumerable<TEnum> instead of a list for the extra LINQ-y flavor, but you can trivially return a real list with .ToList() on the return value.
You could declare your method like this:
public static List<T> Values<T>() where T : struct
{
var type = typeof(T);
if(!type.IsEnum) return null; // or throw exception
return Enum.GetValues(type).Cast<T>().ToList();
}
Then you can call it
Values<BiasCode>();
I'm wondering if I'm missing something because all of the answers use a generic method as part of the solution. Why not just do something like this?
public static List<Enum> Values(this Enum theEnum)
{
return Enum.GetValues(theEnum.GetType()).Cast<Enum>().ToList();
}
The fiddle is here: https://dotnetfiddle.net/FRDuvD
This way this extension method will only be available to enums. Using the generics approach, the extension method seems to be available to all types:
string someString = "x";
someString.Values();
It would be better not to have Values() available to a string at compile time.
How about this
class Program{
static void Main(string[] args)
{
BiasCode b = BiasCode.MPP;
var these = b.Values().ToList();
//... these contains the actual values as the enum type
}
}
public static class EnumExtensions
{
public static IEnumerable<T> Values<T>(this T theEnum) where T : struct,IComparable, IFormattable, IConvertible
{
var enumValues = new List<T>();
if ( !(theEnum is Enum))
throw new ArgumentException("must me an enum");
return Enum.GetValues(typeof(T)).Cast<T>();
}
}
Since you are looking for the extension method, here it is:
public static class EnumExtensions
{
public static List<T> Values<T>(this T theEnum)
where T : struct, IComparable, IFormattable, IConvertible
{
if (!typeof(T).IsEnum)
throw new InvalidOperationException(string.Format("Type {0} is not enum.", typeof(T).FullName));
return Enum.GetValues(theEnum.GetType()).Cast<T>().ToList();
}
}
EDIT
I will incorporate my comment in Bob's answer here:
So, I think we could all agree that there is no best solution for this, since it is not possible to do a where clause constraint on Enum type. Another solution would be to have a following method signature (as Bob suggested):
public static List<Enum> Values(this Enum theEnum)
What we would do better with this solution is the constraint only on Enum values. However, in comparison to the generic solution, we lose the information about the enum type, on which we are invoking your extension method. So we need to cast it again. And I do not see much difference between this and the approach originally posted in by Bob in his question, where he returns List<int> and needs to cast it back to our enum.
The most elegant solution can be achieved by using Code Contracts with static checking. However it requires usage of the code contracts and it would probably an overkill if they are to be used in this single case. This approach was addressed in the following thread: Using code contracts to make a generic to be of type enum
Extension method to get the values of any enum in C#
Based on solutions above with slightly different approach:
public static class Enum<TEnum> where TEnum : struct, IComparable, IFormattable, IConvertible
{
public static IEnumerable<TEnum> GetAll()
{
var t = typeof(TEnum);
if (!t.IsEnum)
throw new ArgumentException();
return Enum.GetValues(t).Cast<TEnum>();
}
}
Usage
var values = Enum<MyEnum>.GetAll();
Test
public enum Test
{
First,
Second,
Third
}
[TestClass]
public class EnumTests
{
[TestMethod]
public void MyTestMethod()
{
var values = Enum<Test>.GetAll();
Assert.AreEqual(3, values.Count());
}
}
.net c# enum extension

Generic extension method for an array does not compile

Populating a request object for a web-service, I need to dynamically add items to some arrays.
I hoped to simplify it by implementing an extension method:
public static class ArrayExtensions<T> where T : class
{
public static T[] Extend<T>(T[] originalArray, T addItem)
{
if (addItem == null)
{
throw new ArgumentNullException("addItem");
}
var arr = new[] { addItem };
if (originalArray == null)
{
return arr;
}
return originalArray.Concat(arr).ToArray();
}
}
So that this old code:
if (foo.bazArr == null)
{
foo.bazArr = new[] { baz };
}
else
{
foo.bazArr = new[] { baz }.Concat(foo.bazArr).ToArray(); // (i know this inserts the new item at the beginning, but that's irrelevant, order doesn't matter)
}
could be rewritten as:
foo.bazArr = foo.bazArr.Extend(baz); // won't compile
The error is: 'System.Array' does not contain a definition for 'Extend' and no extension method 'Extend' accepting a first argument of type 'System.Array' could be found (are you missing a using directive or an assembly reference?)
Whereas calling the extension method directly like so:
foo.bazArr = ArrayExtensions<someService.bazType>.Extend(foo.bazArr, baz);
compiles fine.
Why is that so? Why can't the compiler infer the type on its own here, if the array is strongly-typed?
EDIT - correct code below:
public static class ArrayExtensions
{
public static T[] Extend<T>(this T[] originalArray, T addItem) where T : class
{
if (addItem == null)
{
throw new ArgumentNullException("addItem");
}
var arr = new[] { addItem };
if (originalArray == null)
{
return arr;
}
return originalArray.Concat(arr).ToArray(); // although Concat is not recommended for performance reasons, see the accepted answer
}
}
For this popular question, here's another good simple example:
public static class Extns
{
// here's an unbelievably useful array handling extension for games!
public static T AnyOne<T>(this T[] ra) where T:class
{
int k = ra.Length;
int r = Random.Range(0,k);
return ra[r];
// (add your own check, alerts, etc, to this example code)
}
}
and in use ..
someArrayOfSoundEffects.AnyOne().Play();
someArrayOfAnimations.AnyOne().BlendLeft();
winningDisplay.text = successStringsArray.AnyOne() +", " +playerName;
SpawnEnormousRobotAt( possibleSafeLocations.AnyOne() );
and so on. For any array it will give you one random item. Used constantly in games to randomise effects etc. The array can be any type.
Missing this:
public static T[] Extend<T>(this T[] originalArray, T addItem)
Without the this it is not an extension method.
Additional note: extending an array one item at a time is expensive. A List<T> would be far preferable. Check to see if your web-service tools offer lists as an option.
Even with arrays, using Enumerable.Concat is probably overkill here; I would simply measure the two arrays, allocate a new one, and use the CopyTo method of each to write into place in the new array.
use this in defining extension method
public static T[] Extend<T>(this T[] originalArray, T addItem)
you have missed the "this" keyword

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