Elegantly passing lists and objects as params - c#

In C#, one can use the params keyword to specify an arbitrary number of typed parameters to a method:
public void DoStuff(params Foo[] foos) {...}
public void OtherStuff {
DoStuff(foo1);
DoStuff(foo2, foo3);
}
If you already have a list of objects, you can turn it into an array to pass to this method:
DoStuff(fooList.ToArray());
However, is there any elegant way to mix-n-match? That is, to pass in multiple objects and lists of objects and have the results flattened into one list or array for you? Ideally, I would like to be able to call my method like this:
DoStuff(fooList, foo1, foo2, anotherFooList, ...);
As of right now, the only way I know how to do this is to pre-process everything into one list, and I don't know of any way to do this generically.
Edit: To be clear, I'm not married to the params keyword, it's just a related mechanism that helped me explain what I wanted to do. I'm quite happy with any solution that looks clean and flattens everything into a single list.

You could create a class with implict conversions to wrap a single element and a list:
public class ParamsWrapper<T> : IEnumerable<T>
{
private readonly IEnumerable<T> seq;
public ParamsWrapper(IEnumerable<T> seq)
{
this.seq = seq;
}
public static implicit operator ParamsWrapper<T>(T instance)
{
return new ParamsWrapper<T>(new[] { instance });
}
public static implicit operator ParamsWrapper<T>(List<T> seq)
{
return new ParamsWrapper<T>(seq);
}
public IEnumerator<T> GetEnumerator()
{
return this.seq.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
then you can change your DoStuff method to:
private static void DoStuff(params ParamsWrapper<Foo>[] foos)
{
Foo[] all = foos.SelectMany(f => f).ToArray();
//
}

You can use Enumerable.Concat to join multiple lists and items like:
DoStuff(fooList
.Concat(Enumerable.Repeat(foo1,1))
.Concat(Enumerable.Repeat(foo2,1))
.Concat(Enumerable.Repeat(anotherFooList))
.ToArray();
Note: there are likely much more readable ways to achieve whatever you are trying to do. Even passing IEnumerable<Foo> is more readable.

You can't quite do what you're trying to do, but with an extension method, you could get pretty close:
void Main()
{
var singleFoo = new Foo();
var multipleFoos = new[] { new Foo(), new Foo(), new Foo() };
var count = DoStuffWithFoos(singleFoo.Listify(), multipleFoos).Count();
Console.WriteLine("Total Foos: " + count.ToString());
}
public IEnumerable<Foo> DoStuffWithFoos(params IEnumerable<Foo>[] fooLists)
{
return fooLists.SelectMany(fl => fl); // this flattens all your fooLists into
// a single list of Foos
}
public class Foo { }
public static class ExtensionMethods
{
public static IEnumerable<Foo> Listify(this Foo foo)
{
yield return foo;
}
}

you could make separate methods to load the objects into the same collection, not that elegant but it will work, and the logic is really easy to follow, and not very hard to implement.
public class Flattener<T> : IEnumerable<T>
{
private List<T> _collection = new List<T> ( );
public void Add ( params T [ ] list )
{
_collection.AddRange ( list );
}
public void Add ( params IEnumerable<T> [ ] lists )
{
foreach ( var list in lists )
_collection.AddRange ( list );
}
public T Result
{
get
{
return _collection.ToArray();
}
}
public IEnumerator<T> GetEnumerator ( )
{
return _collection.GetEnumerator ( );
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator ( )
{
return GetEnumerator ( );
}
}
Flattener<Foo> foos = new Flattener();
foos.Add(fooList, fooList2, fooList3,...);
foos.Add(foo1,foo2,foo3,...);
DoStuff(foos.Result);

Related

C# array-like constructor for own class

I want to create a custom class that can be initialized like arrays can,
var myCollection = new MyCollection<string> {"a", "b", "c"}
Is there a syntax for creating a class that can interpret that?
I know how to do a similar thing with class properties, such as
var person = new Person { Name = "Santi", LastName = "Arizti" };
But that is not what I am looking for.
This question might already exist, but I just don't know the name of this feature to effectively search it online.
Your class must
Implement IEnumerable
Have an Add method
That's it.
public class MyCollection<T> : IEnumerable<T>
{
protected readonly List<T> _list = new List<T>();
public void Add(T item)
{
_list.Add(item);
}
IEnumerator IEnumerable.GetEnumerator()
{
return _list.GetEnumerator();
}
public IEnumerator<T> GetEnumerator()
{
return _list.GetEnumerator();
}
}
public class Program
{
public static void Main()
{
var x = new MyCollection<string>
{
"A","B"
};
}
}
Here is a Link to Fiddle
Constructing an object using {...} simply creates it using the default constructor and calls an Add method present on it for each of the arguments (or tuples of arguments if nested {...} is used). It only has to implement IEnumerable.
Your example is essentially equivalent to:
var myCollection = new MyCollection<string>();
myCollection.Add("a");
myCollection.Add("b");
myCollection.Add("c");
Here's the simplest example of such a class that can be "initialized" with anything:
public class TestClass : IEnumerable
{
public void Add<T>(params T[] args)
{
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
}

Generic method to map objects of different types

I would like to write Generic Method that would map List to new list, similar to JS's map method. I would then use this method like this:
var words= new List<string>() { "Kočnica", "druga beseda", "tretja", "izbirni", "vodno bitje" };
List<object> wordsMapped = words.Map(el => new { cela = el, končnica = el.Končnica(5) });
I know there's Select method which does the same thing but I need to write my own method. Right now I have this:
public static IEnumerable<object> SelectMy<T>(this IEnumerable<T> seznam, Predicate<T> predicate)
{
List<object> ret = new List<object>();
foreach (var el in seznam)
ret.Add(predicate(el));
return ret;
}
I also know I could use yield return but again I mustn't. I think the problem is with undeclared types and compiler can't figure out how it should map objects but I don't know how to fix that. All examples and tutorials I found map object of same types.
Linq's Select is the equivalent of the map() function in other functional languages. The mapping function would typically not be called Predicate, IMO - predicate would be a filter which could reduce the collection.
You can certainly wrap an extension method which would apply a projection to map input to output (either of which could be be anonymous types):
public static IEnumerable<TO> Map<TI, TO>(this IEnumerable<TI> seznam,
Func<TI, TO> mapper)
{
foreach (var item in seznam)
yield return mapper(item);
}
Which is equivalent to
public static IEnumerable<TO> Map<TI, TO>(this IEnumerable<TI> seznam,
Func<TI, TO> mapper)
{
return seznam.Select(mapper);
}
And if you don't want a strong return type, you can leave the output type as object
public static IEnumerable<object> Map<TI>(this IEnumerable<TI> seznam, Func<TI, object> mapper)
{
// Same implementation as above
And called like so:
var words = new List<string>() { "Kočnica", "druga beseda", "tretja", "izbirni", "vodno bitje" };
var wordsMapped = words.Map(el => new { cela = el, končnica = el.Končnica(5) });
Edit
If you enjoy the runtime thrills of dynamic languages, you could also use dynamic in place of object.
But using dynamic like this so this precludes the using the sugar of extension methods like Končnica - Končnica would either need to be a method on all of the types utilized, or be invoked explicitly, e.g.
static class MyExtensions
{
public static int Končnica(this int i, int someInt)
{
return i;
}
public static Foo Končnica(this Foo f, int someInt)
{
return f;
}
public static string Končnica(this string s, int someInt)
{
return s;
}
}
And then, provided all items in your input implemented Končnica you could invoke:
var things = new List<object>
{
"Kočnica", "druga beseda",
53,
new Foo()
};
var mappedThings = things.Map(el => new
{
cela = el,
končnica = MyExtensions.Končnica(el, 5)
// Or el.Končnica(5) IFF it is a method on all types, else run time errors ...
})
.ToList();
You can fix your code to work correctly like this:
public static IEnumerable<TResult> SelectMy<T, TResult>(this IEnumerable<T> seznam,
Func<T, TResult> mapping)
{
var ret = new List<TResult>();
foreach (var el in seznam)
{
ret.Add(mapping(el));
}
return ret;
}
Note that this is inefficient and problematic compared to typical Linq extensions, because it enumerates the entire input at once. If the input is an infinite series, you are in for a bad time.
It is possible to remedy this problem without the use of yield, but it would be somewhat lengthy. I think it would be ideal if you could tell us all why you are trying to do this task with two hands tied behind your back.
As a bonus, here is how you could implement this with the lazy evaluation benefits of yield without actually using yield. This should make it abundantly clear just how valuable yield is:
internal class SelectEnumerable<TIn, TResult> : IEnumerable<TResult>
{
private IEnumerable<TIn> BaseCollection { get; set; }
private Func<TIn, TResult> Mapping { get; set; }
internal SelectEnumerable(IEnumerable<TIn> baseCollection,
Func<TIn, TResult> mapping)
{
BaseCollection = baseCollection;
Mapping = mapping;
}
public IEnumerator<TResult> GetEnumerator()
{
return new SelectEnumerator<TIn, TResult>(BaseCollection.GetEnumerator(),
Mapping);
}
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
}
internal class SelectEnumerator<TIn, TResult> : IEnumerator<TResult>
{
private IEnumerator<TIn> Enumerator { get; set; }
private Func<TIn, TResult> Mapping { get; set; }
internal SelectEnumerator(IEnumerator<TIn> enumerator,
Func<TIn, TResult> mapping)
{
Enumerator = enumerator;
Mapping = mapping;
}
public void Dispose() { Enumerator.Dispose(); }
public bool MoveNext() { return Enumerator.MoveNext(); }
public void Reset() { Enumerator.Reset(); }
public TResult Current { get { return Mapping(Enumerator.Current); } }
object IEnumerator.Current { get { return Current; } }
}
internal static class MyExtensions
{
internal static IEnumerable<TResult> MySelect<TIn, TResult>(
this IEnumerable<TIn> enumerable,
Func<TIn, TResult> mapping)
{
return new SelectEnumerable<TIn, TResult>(enumerable, mapping);
}
}
The problem with your code is that Predicate<T> is a delegate that returns a boolean, which you're then trying to add to a List<object>.
Using a Func<T,object> is probably what you're looking for.
That being said, that code smells bad:
Converting to object is less than useful
Passing a delegate that maps T to an anonymous type won't help - you'll still get an object back which has no useful properties.
You probably want to add a TResult generic type parameter to your method, and take a Func<T, TResult> as an argument.

C# Cast List of MyType to List of objects

I'm writing an application where I am required to use Reflection to call a method which has parameters of type MyObject.
Method (List<MyObject> input , out List<MyObject> output,..... );
Using reflection I send the parameter of type Object. How can I cast List<MyObject> to List<object>
var parameters = new Object[] { inputs, outputs, userPrams };
System.Type classType = typeof(MyClass);
object instance = Activator.CreateInstance(classType);
classType.InvokeMember(name, BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public,null, instance, parameters);
In the code above both input and output are lists of type MyObject
I tried to Cast them to List of Objects but this doesn't work
x.Outputs = grOutputs as IList<object>
Can anyone help?
Your question is not 100% clear, so I assumed the problem you're facing is the one you put in the title:
Cast List of MyType to List of objects
As #Charles said, IList<T> and List<T> are not variant, so you can't cast IList<DerivedClass> to IList<BaseClass>. You have to create new List<BaseClass>.
There are many ways to do that, I think there are two you should consider:
You can use Cast and ToList, but it will require using System.Linq.
var listOfStrings = new List<string>() { "foo", "bar" };
var listOfObjects = listOfStrings.Cast<object>().ToList();
To avoid that, you can use new List<T>(IEnumerable<T> source) constructor. Because IEnumerable<T> is covariant, you can do following:
var listOfStrings = new List<string>() { "foo", "bar" };
var listOfObjects = new List<object>(listOfString);
You might well want to do something like this:
var dogs = new List<Dog>();
var pets = (List<object>)dogs;
pets.Add(new Cat());
The C# language is heavily invested in you stop mixing cats and dogs like this. It violates the hard guarantee that the list only ever contains dogs. You'll have to do it like this instead:
var dogs = new List<Dog>();
var pets = new List<object>(dogs);
pets.Add(new Cat());
Which is fine, it creates a new list, one that no longer guarantees that it only ever contains dogs since it only promises that the list contains object. Pretty useless, typically, you basically lose all knowledge of what the list contains. Forcing you to write hunt-the-fox code that uses the as operator or Reflection to find the proper animal back. Code that fails to do its job at run-time instead of the compiler telling you that its wrong code at build time, when you're still in the comfortable cubicle cocoon.
Which it did.
IList<T> is not covariant, you would need to create a new list if you wanted IList<object>:
x.Outputs = grOutputs.Cast<object>().ToList();
If I understand your question, you could try something like this :
var objList = myClassList.OfType<object>();
You cannot make your desired cast because, as others have written, collections in c# are not covariant.
You can either create a new list, or introduce a ListWrapper class like so:
public class ListWrapper<TOut, TIn> : IList<TOut> where TIn : class, TOut where TOut : class
{
readonly IList<TIn> list;
public ListWrapper(IList<TIn> list)
{
if (list == null)
throw new NullReferenceException();
this.list = list;
}
#region IList<TOut> Members
public int IndexOf(TOut item)
{
TIn itemIn = item as TIn;
if (itemIn != item)
return -1;
return list.IndexOf(itemIn);
}
public void Insert(int index, TOut item)
{
list.Insert(index, (TIn)item);
}
public void RemoveAt(int index)
{
list.RemoveAt(index);
}
public TOut this[int index]
{
get
{
return list[index];
}
set
{
list[index] = (TIn)value;
}
}
#endregion
#region ICollection<TOut> Members
public void Add(TOut item)
{
list.Add((TIn)item);
}
public void Clear()
{
list.Clear();
}
public bool Contains(TOut item)
{
TIn itemIn = item as TIn;
if (itemIn != item)
return false;
return list.Contains(itemIn);
}
public void CopyTo(TOut[] array, int arrayIndex)
{
foreach (var item in list)
{
array[arrayIndex] = item;
arrayIndex++;
}
}
public int Count
{
get { return list.Count; }
}
public bool IsReadOnly
{
get
{
return list.IsReadOnly;
}
}
public bool Remove(TOut item)
{
return list.Remove(item as TIn);
}
#endregion
#region IEnumerable<TOut> Members
public IEnumerator<TOut> GetEnumerator()
{
foreach (var item in list)
yield return item;
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
}
You might want to make the wrapper read-only since the setter could throw an exception if the incoming object is not of the inner list's item type.

C# Passing an array of Func<T, List<myClass>> to a method

My first (and really horrible post) is below.
I try to do a complete example what I want to get. I hope this will be left explained a bit better.
using System;
using System.Collections.Generic;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List<Boy> boys = new List<Boy>();
boys.Add(new Boy("Jhon", 7));
boys.Add(new Boy("Oscar", 6));
boys.Add(new Boy("Oscar", 7));
boys.Add(new Boy("Peter", 5));
ClassRoom myClass = new ClassRoom(boys);
Console.WriteLine(myClass.ByName("Oscar").Count); // Prints 2
Console.WriteLine(myClass.ByYearsOld(7).Count); // Prints 2
// This has errors...................
// But this is as I would like to call my BySomeConditions method....
Console.WriteLine( // It should print 1
myClass.BySomeConditions([myClass.ByName("Oscar"),
myClass.ByYearsOld(7)]
)
);
Console.ReadKey();
}
class ClassRoom
{
private List<Boy> students;
public ClassRoom(List<Boy> students)
{
this.students = students;
}
public List<Boy> ByName(string name)
{
return students.FindAll(x => x.Name == name);
}
public List<Boy> ByYearsOld(int yearsOld)
{
return students.FindAll(x => x.YearsOld == yearsOld);
}
// This has ERRORS.......................
public List<Boy> BySomeConditions(params Func<X, List<Boy>>[] conditions)
{
IEnumerable<Boy> result = students;
foreach (var condition in conditions) {
// I want it ONLY be called with existent functions (ByName and/or ByYearsOld)
result = result.Intersect(condition(this));
}
}
}
class Boy
{
public string Name { get; set; }
public int YearsOld { get; set; }
public Boy(string name, int yearsOld)
{
Name = name;
YearsOld = yearsOld;
}
}
}
}
============== first post =====================
Hello,
I have a class with methods:
public class X
{
private readonly List<string> myList;
public X(List<string> paramList) // string is really an object
{
myList = paramList;
}
// Now I want this...
public List<string> CheckConditions(params Func<T, List<string>>[] conditions)
{
var result = myList;
foreach (Func<T, List<string>> condition in conditions)
{
result = result.Intersect(condition(T));
}
}
public List<string> check1(string S)
{
return myList.FindAll(x => x.FieldS == S);
}
public List<string> check1(int I)
{
return myList.FindAll(x => x.FieldI == I);
}
}
Sorry if there is some error, I have written from scrach to avoid complex real case.
What I want is call my methods like this:
X.check1("Jhon");
or
X.check2(12);
or (this is the goal of my question):
X.CheckConditions(X.check1("Jhon"), X.chek2(12));
Thanks and sorry by my poor example...
It is unclear where your T comes from.
Does this meet your requirements?
public class X<T>
{
private List<T> myList;
public List<T> CheckConditions(params Func<T, bool>[] conditions)
{
IEnumerable<T> query = myList;
foreach (Func<T, bool> condition in conditions)
{
query = query.Where(condition);
}
return query.ToList();
}
}
Then later:
List<T> result = X.CheckConditions(
z => z.FieldS == "Jhon",
z => z.FieldI == 12
);
You need to change the method signature of CheckConditions, it's accepting a variable number of List<string>, not functions.
public List<string> CheckConditions(params List<string>[] lists)
The return type of check1 is List<string>, so that needs to be the type of the parameter that CheckConditions accepts.
There's no reason to make it generic, you know that you want to operate on the current instance of X (so pass in this, instead of the T type parameter). You need to cleanup a few things to to get it to compile (return result and make the type of result and the Intersect call compatible). You can define it like this:
public List<string> CheckConditions(params Func<X, List<string>>[] conditions)
{
IEnumerable<string> result = myList;
foreach (var condition in conditions)
{
result = result.Intersect(condition(this));
}
return result.ToList();
}
Ant then call it like this:
xInstance.CheckConditions(x => x.check1("JHon"), x => x.check1(12));
All that said, I'm not sure why you wouldn't just pass around the results of these functions, instead of passing the actual functions around:
public List<string> CheckConditions(params List<string>[] conditions)
{
IEnumerable<string> result = myList;
foreach (var condition in conditions)
{
result = result.Intersect(condition);
}
return result.ToList();
}
Then call it as in your example, rather than passing in lambda expressions.
you could rewrite you function to look like this:
// Now I want this...
public List<string> CheckConditions(params Func<T, List<string>>[] conditions)
{
var result = myList;
foreach (Func<T, List<string>> condition in conditions)
{
result = result.Intersect(condition(T));
}
}
your call would then be X.CheckConditions(()=>X.check1("Jhon"), ()=>X.chek2(12));
and you need to provide an instance for x (since the methods are instance methods and not static methods)
In your example you pass T as an argument to the functor but T is a type argument som it can't be passed as an argument to the method. Did you mean to pass a value?
This begs for a clarification of why you would want to do this. Maybe if you provided details on what you are trying to accomplish (as opposed to how) then you could get a better solution to your problem.
What you pass to your
X.CheckConditions
is not a reference to the functions, but the returned value of their invocation.
Now, if you pass function reference - it does not come with parameters, unless you construct and pass a data-structure that will contain the function reference and the arguments it should work on.
In this case - generics is not the solution. You should consider another pattern to follow, like command pattern or strategy pattern, where you pass to your CheckConstruction instances of checker-objects, each is instantiated with the parameters it should work on, and either implements or is provided by the validation function.

How should I use properties when dealing with read-only List<T> members

When I want to make a value type read-only outside of my class I do this:
public class myClassInt
{
private int m_i;
public int i {
get { return m_i; }
}
public myClassInt(int i)
{
m_i = i;
}
}
What can I do to make a List<T> type readonly (so they can't add/remove elements to/from it) outside of my class? Now I just declare it public:
public class myClassList
{
public List<int> li;
public myClassList()
{
li = new List<int>();
li.Add(1);
li.Add(2);
li.Add(3);
}
}
You can expose it AsReadOnly. That is, return a read-only IList<T> wrapper. For example ...
public ReadOnlyCollection<int> List
{
get { return _lst.AsReadOnly(); }
}
Just returning an IEnumerable<T> is not sufficient. For example ...
void Main()
{
var el = new ExposeList();
var lst = el.ListEnumerator;
var oops = (IList<int>)lst;
oops.Add( 4 ); // mutates list
var rol = el.ReadOnly;
var oops2 = (IList<int>)rol;
oops2.Add( 5 ); // raises exception
}
class ExposeList
{
private List<int> _lst = new List<int>() { 1, 2, 3 };
public IEnumerable<int> ListEnumerator
{
get { return _lst; }
}
public ReadOnlyCollection<int> ReadOnly
{
get { return _lst.AsReadOnly(); }
}
}
Steve's answer also has a clever way to avoid the cast.
There is limited value in attempting to hide information to such an extent. The type of the property should tell users what they're allowed to do with it. If a user decides they want to abuse your API, they will find a way. Blocking them from casting doesn't stop them:
public static class Circumventions
{
public static IList<T> AsWritable<T>(this IEnumerable<T> source)
{
return source.GetType()
.GetFields(BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance)
.Select(f => f.GetValue(source))
.OfType<IList<T>>()
.First();
}
}
With that one method, we can circumvent the three answers given on this question so far:
List<int> a = new List<int> {1, 2, 3, 4, 5};
IList<int> b = a.AsReadOnly(); // block modification...
IList<int> c = b.AsWritable(); // ... but unblock it again
c.Add(6);
Debug.Assert(a.Count == 6); // we've modified the original
IEnumerable<int> d = a.Select(x => x); // okay, try this...
IList<int> e = d.AsWritable(); // no, can still get round it
e.Add(7);
Debug.Assert(a.Count == 7); // modified original again
Also:
public static class AlexeyR
{
public static IEnumerable<T> AsReallyReadOnly<T>(this IEnumerable<T> source)
{
foreach (T t in source) yield return t;
}
}
IEnumerable<int> f = a.AsReallyReadOnly(); // really?
IList<int> g = f.AsWritable(); // apparently not!
g.Add(8);
Debug.Assert(a.Count == 8); // modified original again
To reiterate... this kind of "arms race" can go on for as long as you like!
The only way to stop this is to completely break the link with the source list, which means you have to make a complete copy of the original list. This is what the BCL does when it returns arrays. The downside of this is that you are imposing a potentially large cost on 99.9% of your users every time they want readonly access to some data, because you are worried about the hackery of 00.1% of users.
Or you could just refuse to support uses of your API that circumvent the static type system.
If you want a property to return a read-only list with random access, return something that implements:
public interface IReadOnlyList<T> : IEnumerable<T>
{
int Count { get; }
T this[int index] { get; }
}
If (as is much more common) it only needs to be enumerable sequentially, just return IEnumerable:
public class MyClassList
{
private List<int> li = new List<int> { 1, 2, 3 };
public IEnumerable<int> MyList
{
get { return li; }
}
}
UPDATE Since I wrote this answer, C# 4.0 came out, so the above IReadOnlyList interface can take advantage of covariance:
public interface IReadOnlyList<out T>
And now .NET 4.5 has arrived and it has... guess what...
IReadOnlyList interface
So if you want to create a self-documenting API with a property that holds a read-only list, the answer is in the framework.
JP's answer regarding returning IEnumerable<int> is correct (you can down-cast to a list), but here is a technique that prevents the down-cast.
class ExposeList
{
private List<int> _lst = new List<int>() { 1, 2, 3 };
public IEnumerable<int> ListEnumerator
{
get { return _lst.Select(x => x); } // Identity transformation.
}
public ReadOnlyCollection<int> ReadOnly
{
get { return _lst.AsReadOnly(); }
}
}
The identity transformation during enumeration effectively creates a compiler-generated iterator - a new type which is not related to _lst in any way.
Eric Lippert has a series of articles on Immutability In C# on his blog.
The first article in the series can be found here.
You might also find useful Jon Skeet's answer to a similar question.
public List<int> li;
Don't declare public fields, it's generally considered bad practice... wrap it in a property instead.
You can expose your collection as a ReadOnlyCollection :
private List<int> li;
public ReadOnlyCollection<int> List
{
get { return li.AsReadOnly(); }
}
public class MyClassList
{
private List<int> _lst = new List<int>() { 1, 2, 3 };
public IEnumerable<int> ListEnumerator
{
get { return _lst.AsReadOnly(); }
}
}
To check it
MyClassList myClassList = new MyClassList();
var lst= (IList<int>)myClassList.ListEnumerator ;
lst.Add(4); //At this point ypu will get exception Collection is read-only.
public static IEnumerable<T> AsReallyReadOnly<T>(this IEnumerable<T> source)
{
foreach (T t in source) yield return t;
}
if I add to Earwicker's example
...
IEnumerable<int> f = a.AsReallyReadOnly();
IList<int> g = f.AsWritable(); // finally can't get around it
g.Add(8);
Debug.Assert(a.Count == 78);
I get InvalidOperationException: Sequence contains no matching element.

Categories

Resources