Is this GetEnumAsStrings<T>() method reinventing the wheel? - c#

I have a number of enums and need to get them as List<string> objects in order to enumerate through them and hence made the GetEnumAsStrings<T>() method.
But it seems to me there would be an easier way.
Is there not a built-in method to get an enum like this into a List<string>?
using System;
using System.Collections.Generic;
namespace TestEnumForeach2312
{
class Program
{
static void Main(string[] args)
{
List<string> testModes = StringHelpers.GetEnumAsStrings<TestModes>();
testModes.ForEach(s => Console.WriteLine(s));
Console.ReadLine();
}
}
public static class StringHelpers
{
public static List<string> GetEnumAsStrings<T>()
{
List<string> enumNames = new List<string>();
foreach (T item in Enum.GetValues(typeof(TestModes)))
{
enumNames.Add(item.ToString());
}
return enumNames;
}
}
public enum TestModes
{
Test,
Show,
Wait,
Stop
}
}
Addendum:
Thanks everyone, very insightful. Since I ultimately needed this for Silverlight which doesn't seem to have GetValues() or GetNames() for enums, I made this method which I created from this method:
public static List<string> ConvertEnumToListOfStrings<T>()
{
Type enumType = typeof(T);
List<string> strings = new List<string>();
var fields = from field in enumType.GetFields()
where field.IsLiteral
select field;
foreach (FieldInfo field in fields)
{
object value = field.GetValue(enumType);
strings.Add(((T)value).ToString());
}
return strings;
}

You could do it as a one-liner using LINQ:
var enums = Enum.GetNames(typeof(TestModes)).ToList();
Now, keep in mind that GetNames returns an array of strings... so you might not even need ToList().
Edit:
There are ways to improve on your edited code. Here's a simple one that uses ToList rather than explicitly instantiating the list:
public static List<string> ConvertEnumToListOfStrings<T>()
{
Type enumType = typeof(T);
var fields = from field in enumType.GetFields()
where field.IsLiteral
select ((T)field.GetValue(enumType)).ToString();
return fields.ToList();
}
And this next one is my personal preference. Why instantiate a list at all? You probably just need to iterate over the names, not add or remove them from a list. So just use IEnumerable and don't bother building the list at all. Saves you one (admittedly small) iteration and the memory overhead of another object.
public static IEnumerable<string> GetEnumNames<T>()
{
Type enumType = typeof(T);
var fields = from field in enumType.GetFields()
where field.IsLiteral
select ((T)field.GetValue(enumType)).ToString();
return fields;
}

MSDN - Enum.GetNames
So for your example it would be:
List<string> testModes = Enum.GetNames(typeof(TestModes)).ToList();
Or, if you're still back in .NET 2.0
List<string> testModes = new List<string>(Enum.GetNames(typeof(TestModes)));
If you really need it as a List<string>, otherwise I would just work directly with the array.

Related

How to Access elements in a List<T> when T is only stored in a Type Variable?

I'll try to make this clear:
I have an object of type System.Object that contains a List of things. The things are determined at runtime. Currently, I'm able to find out the type of things contained in the list, but I can't figure out how to access them.
Here's a code example where "o" is the List of things in question:
Example:
//Assume at this point in code, we have access to "o"
//which is type System.Object
Type thingType = thing.GetType();
Type listType = typeof(List<>);
Type listOfThingsType = listType.MakeGenericType(thingType);
if (o.GetType() == listOfThingsType)
{
//Now I know o contains a list of things
//...but how do I access them and work with their members?
//foreach thing in o
// operate on thing through reflection
}
EDIT (more details):
I'm using reflection to access property members of things. I don't know what the property names are. I don't need to be able to use normal C# syntax. I just need a way to access the things so I can use reflection on them as individual objects.
List<T> implements IList. If all you need is access to the instances that make up the list for serialization (or whatever) use List instead of List<T> as it seems like the actual type might not really matter. Of course that might depend on the serializer you are using too (you mentioned that in your comment?).
Fiddle
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
public class Program
{
public class MyType
{
public string Name {get;set;}
public MyType(){}
public MyType(string name) {
this.Name = name;
}
public override string ToString()
{
return this.Name ?? "empty";
}
}
public static void Main()
{
List<MyType> list = new List<MyType>();
list.Add(new MyType("One"));
list.Add(new MyType("Two"));
DoSomethingWithUnknown(list);
}
public static void DoSomethingWithUnknown(object argList)
{
var list = (IList)argList;
foreach(var item in list)
{
Console.WriteLine("As object: " + item);
dynamic itm = item;
Console.WriteLine("As dynamic: " + itm.Name);
}
}
}
Thank you to HansPassant, who suggested using dynamic.
Here is the solution:
//Assume at this point in code, we have access to "o"
//which is type System.Object
Type thingType = thing.GetType();
Type listType = typeof(List<>);
Type listOfThingsType = listType.MakeGenericType(thingType);
if (o.GetType() == listOfThingsType)
{
//Now I know o contains a list of things
//...but how do I access them and work with their members?
dynamic oList = o;
foreach(object thing in oList)
{
//operate on thing through reflection
}
}

Distinct Function C#

Edit:
The original question was based on this code that I saw below elsewhere:
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main()
{
// List with duplicate elements.
List<int> list = new List<int>();
list.Add(1);
list.Add(2);
list.Add(3);
list.Add(3);
list.Add(4);
list.Add(4);
list.Add(4);
foreach (int value in list)
{
Console.WriteLine("Before: {0}", value);
}
// Get distinct elements and convert into a list again.
List<int> distinct = list.Distinct().ToList();
foreach (int value in distinct)
{
Console.WriteLine("After: {0}", value);
}
}
}
I apologize for my question was not specific enough.
Distinct is similar to distinct in a SQL Query .
Ex: var distinctElements = duplicatedElements.Distinct();
The above code filters out duplicate entries and returns an IEnumerable<T> of distinct elements. The original duplicatedElements is left intact though
Distinct does not do this, as Eric says. Instead, it feeds you distinct elements of a container in an IEnumerable<T>. The exact implementation of Distinct actually varies on the container.
Consider the following code snippet:
public static class StaticyGoodness
{
public static void Main()
{
var someAs = new List<A>();
var someBs = new List<B>(); // get it?
DoTheThings(someAs);
// Doing things the regular way
DoTheThings(someBs);
// Doing things the SPECIALIZED way
DoTheThings(someBs.OrderBy(b => b.Stuff));
// Doing things the REALLY SPECIALIZED way
}
private static void DoTheThings<T>(this IEnumerable<T> source)
{
Console.WriteLine("Doing things the regular way");
}
private static void DoTheThings(this IEnumerable<B> source)
{
Console.WriteLine("Doing things the SPECIALIZED way");
}
private static void DoTheThings(this IOrderedEnumerable<B> source)
{
Console.WriteLine("Doing things the REALLY SPECIALIZED way");
}
}
public class A { }
public class B : A { public int Stuff { get; set; } }
Depending on what exactly you give to the DoTheThings function, a different overload gets bound at compile time. I found this surprising. I thought the runtime would choose a better candidate, if there was one, at runtime based on the thing's actual type instead of its declared type.
For example, if we extract the OrderBy expression to a local variable, declaring it as IEnumerable<B> instead of IOrderedEnumerable<B> (e.g. we are returning from a repository method but don't want to expose the implementation detail of its having been sorted), the REALLY SPECIALIZED call would not be made.
IEnumerable<B> plainEnumerable = someBs.OrderBy(b => b.Stuff);
DoTheThings(plainEnumerable);
// Doing things the SPECIALIZED way :( (ed.)

How to specify a list selection method?

I've got a method that computes a list. At certain points in the algorithm a single element from the list needs to be chosen. It doesn't really matter which element is chosen, but I'd like to leave it up to the user to decide.
Right now, I've added an extension method IList<T>.Random() which simply takes a random element. .First() would have worked equally as well. Supposing I want to let the user pick which method is used, or perhaps an entirely different method, how would that look?
I was thinking about using an enum with limited options, and then I could wrap each of these calls in a switch and call the appropriate function. But maybe some sort of lambda function would be more appropriate?
This method needs to be used in two different places, once on a List<char> and once on a List<string>. I want to use the same method for both.
This isn't a GUI app. I'm trying to decide how to design the API.
Specifically, I want to have a field like
public Func<IList<T>, T> SelectElement = list => list.First();
Which would then be used in the method,
public string Reverse(string pattern, IList<object> args = null, IDictionary<string, object> kwargs = null)
But generic fields aren't possible. So I'm looking for an alternative solution. One would be to make the SelectElement method an argument to Reverse(), then I could make it generic... but I was hoping to keep it at a class-level for re-usability. Don't want to pass any more args to the function if I can help it.
Edit: full source code
how about this:
public class MyClass
{
public static class C<T>
{
public static Func<IList<T>, T> SelectElement;
}
public int Test(IList<int> list)
{
return C<int>.SelectElement(list);
}
}
static class Program
{
static void Main(string[] args)
{
MyClass.C<char>.SelectElement = xs => xs.First();
MyClass.C<int>.SelectElement = xs => xs.First();
var list = new List<int>(new int[] { 1, 2, 3 });
var c = new MyClass();
var v = c.Test(list);
Console.WriteLine(v);
}
}
Here's an extremely basic example I put together using a generic method that takes in a Func<IEnumerable<T>, T> for selecting an item from the list and then returns the result. I've done a few examples of how to call it:
using System;
using System.Collections.Generic;
using System.Linq;
namespace Test
{
class Program
{
static void Main(string[] args)
{
//Simple list.
var list = new List<int> { 1, 2, 3, 4 };
// Try it with first
var result = DoItemSelect(list, Enumerable.First);
Console.WriteLine(result);
// Try it with last
result = DoItemSelect(list, Enumerable.Last);
Console.WriteLine(result);
// Try it with ElementAt for the second item (index 1) in the list.
result = DoItemSelect(list, enumerable => enumerable.ElementAt(1));
Console.WriteLine(result);
}
public static T DoItemSelect<T>(IEnumerable<T> enumerable, Func<IEnumerable<T>, T> selector)
{
// You can do whatever you method does here, selector is the user specified func for
// how to select from the enumerable. Here I just return the result of selector directly.
return selector(enumerable);
}
}
}
If you want to limit the choices a user has you could follow the route of an enum and make this method a private method and then have a way to convert the enum to the appropriate selector delegate to pass to the underlying private method.
public Func<IList<object>, object> SelectElement = list => list.First();
private T _S<T>(IEnumerable<T> list)
{
return (T)SelectElement(list.Cast<object>().ToList());
}
I can make the anonymous method work on objects, thereby avoiding generics, and then add a helper method which is what I'll actually use to call it. A little ugly, but seems to work.
This works for chars and strings. Haven't tested with other types. Built this before I saw Ralph's code, which is practically the same.
LINQPad code:
void Main()
{
var chars = new List<char>();
var strings = new List<string>();
chars.AddRange(new char[] {'1','2','4','7','8','3'});
strings.AddRange(new string[] {"01","02","09","12","28","52"});
chars.Dump();
strings.Dump();
Func<IList<object>, string> SelectFirst = ( list )
=> list.First().ToString();
Func<IList<object>, string> SelectLast = ( list )
=> list.Last().ToString();
Func<IList<object>, string> SelectRandom = ( list )
=> list.ElementAt( new Random().Next(0, list.Count())).ToString();
SelectBy(SelectFirst, strings.Cast<object>().ToList()).Dump();
SelectBy(SelectFirst, chars.Cast<object>().ToList()).Dump();
SelectBy(SelectLast, strings.Cast<object>().ToList()).Dump();
SelectBy(SelectLast, chars.Cast<object>().ToList()).Dump();
SelectBy(SelectRandom, strings.Cast<object>().ToList()).Dump();
SelectBy(SelectRandom, chars.Cast<object>().ToList()).Dump();
}
private string SelectBy(Func<IList<object>, string> func, IList<object> list)
{
return func(list);
}

enumerate through all IEnumerables

I need to send different IEnumerables to an Printer object.
This printer object will then do something to them, inside a foreach loop.
class Printer
{
public Printer(IEnumerable list)
{
foreach (var enumerable in list)
{
//DO STUFF
}
}
}
This lets me send any enumerable, such as an List<T> to the printer object.
such as
var list = new List<string> {"myList"};
new Printer(list); //mylist
This works fine.
BUT if I send a Dictionary<T, T> such as:
var dictionary = new Dictionary<int, string> {{1, "mydict"}};
new Printer(dictionary); //[1, mydict]
It'll have a key and a value. What I would want though, would be separate access to the Value property inside the foreach loop. All I DO have access to is the enumerable object, which has no properties I can use.
Now what if the datatype T is an object containing several properties (this goes for both examples). How would I be able to use these properties in my foreach loop?
Do I honestly have to create an overload of the constructor, foreach possible datatype I might send down to it?
Also, all I need to do in the foreach is not dependable to any datatypes - as it won't manipulate everything. I do need ACCESS to all the properties though.
Also, this is just example code, not actually the production-code I use in my application.
Can you change the code of the Printer class? If it accepted something like an IEnumerable<IPrintable> instead of just an IEnumerable it would be easier. With an interface like this:
interface IPrintable
{
void Print();
}
Then all objects that would be sent to the Printer would need to implement that interface. Then you could do:
class Printer
{
public Printer(IEnumerable<IPrintable> list)
{
foreach (var enumerable in list)
{
enumerable.Print();
}
}
}
And if you have a dictionary of printable objects, something like:
var dict = new Dictionary<int,IPrintable>();
You could just pass the values to the function:
var printer = new Printer(dict.Values);
You could modify your method to accept a delegate that returns the data the print method needs. Something like this:
// You will not need this class, if you always want a single string result.
class PrinterData
{
public string Value { get; set; }
// More properties?
}
class Printer
{
public Printer<T>(IEnumerable<T> list, Func<T, PrinterData> func)
{
foreach (T item in list)
{
PrinterData data = func(item);
// Do something with the data.
}
}
}
Usage:
int[] ints = new int[] {1,2,3};
new Printer().Print(ints, x => new PrinterData() { Value = x.ToString() });
var dictionary = new Dictionary<int, string> {{1, "mydict"}};
new Printer().Print(dictionary, x => new PrinterData() { Value = x.Name + " = " + x.Value });
Per Erik Stendahl's answer is very similar.
You have to extract an enumerable with the values you want to pass before you call new Printer(). In the case of the dictionary this is simple: just use dict.Values. A more general case is:
var list = List<MyObject>()...
var printer = new Printer(list.Select(x => x.MyProperty));
If you want to treat different types differently, you probably should make different methods. If you want to treat them the same, you should accept a common interface, and only use the methods defined for the interface.
It would be possible to do
if (list is Dictionary<int, string>) {
// do special case
}
but I shudder at the thought.
You can even check generically:
class Printer<T>
{
public Printer<T>(IEnumerable list)
{
foreach (var enumerable in list)
{
if (list is Dictionary<T, T>) {
//DO STUFF
}
}
}
}
The problem is that a collection, though it is enumerable, can hold different types of objects, as you saw with the difference between the List and the Dictionary.
To get around this without coding for each object type, you'd have to only accept an enumerable collection of a certain type that you define, for example IEnumerable<IMyType>.
If you can't do anything at the callee, it's up to the caller to make sure it passes an IEnumerable that is "valid" for Printer, like passing dictionary.Values instead of dictionary in your example. However if the class is public and will be used by 3rd party users, you're better to add some generic constraint to your IEnumerable, as others stated.
Here is the result:
I used your guys help, so I guess I shouldn't vote my own as the answer.
class Printer
{
public Printer(IEnumerable<IPrintable> list) //Accepts any collection with an object that implements IPrintable interface
{
foreach (var enumerable in list) //iterate through list of objects
{
foreach (var printable in enumerable)//loops through properties in current object
{
//DO STUFF
}
}
}
}
interface IPrintable : IEnumerable { }
class SomeObject : IPrintable
{
public string Property1 { get; set; }
public string Property2 { get; set; }
public interface IEnumerable
{
IEnumerator GetEnumerator(); //Returns a Enumerator
}
public IEnumerator GetEnumerator()
{
yield return Property1;
yield return Property2;
}
}
I'd naturally need to implement custom GetEnumerator() foreach object - no problem though!

Generics List with Array return but how?

These Codes really boring. And Tostring() give me error !!! Can you rearrange these codes ?
class Program
{
static void Main(string[] args)
{
string[] arraystr = { "yusuf", "mehmet" };
Ilist myitems = new Ilist(arraystr);
SelectedItemsList slist = new SelectedItemsList();
slist.Items.Add(myitems);
Console.Write(slist.Items[0].ToString());
Console.ReadKey();
}
}
public class Ilist
{
private string[] Ad;
public Ilist(string[] ad)
{
Ad = ad;
}
public override string[] ToString()
{
return this.Ad;
}
}
public class SelectedItemsList
{
public List<Ilist> Items;
public SelectedItemsList()
{
Items = new List<Ilist>();
}
}
error :
Generics_List_with_Class.Ilist.ToString()': return type must be 'string' to match overridden member 'object.ToString()'
Rename Ilist.ToString() to ToStringArray(). All objects have a ToString() method but you're overriding it with a function with a different return type, causing your error.
IList isn't a good name for a class, because convention dicates that names starting with "I" should be interfaces. I recommend Ilist should look more like this:
public class StringList
{
private string[] Ad;
public StringList(string[] ad)
{
Ad = ad;
}
public string[] ToStringArray()
{
return this.Ad;
}
public override ToString()
{
return string.Join(",", Ad);
}
}
To be honest though, I recommend you ditch this whole approach and look into using List instead.
The method you are overriding has a return type of string. If you override a method, it's method signature (it's return type, name and arguments) should remain the same (well, there are cases where it can be different, but for now assume they should be the same). So your ToString() method must look like this:
public override string ToString()
{
...
}
It's up to you to decide what the best string representation is, but if you want to use ToString() it must return a string.
As Neil Barnwell suggests if you actually just want to return an array you could rename your current method to something like:
public string[] GetItems()
{
return Ad;
}
or if you do want a string you could make your ToString method something like this:
public override string ToString()
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("{ ");
stringBuilder.Append(string.Join(", ", Ad));
stringBuilder.Append(" }");
return stringBuilder.ToString();
}
Depending on whether you are doing this to learn C# or whether it's actual code, I would look at:
List<string> list = new List<string>()
{
"yusef",
"mehmet",
};
if you are using C# 3.0, or if not:
List<string> myitems = new List<string>();
myitems.AddRange(arraystr);
If you're using C# 3.0 you can use the extension methods in the System.Linq namespace to make it easy:
IList<string> list = new List<string>();
list.Add("item1");
list.Add("item2");
string[] array = list.ToArray();
Your ToString function returns a string array, whereas the method it overrides from object should return a single string.
Also, naming your class IList doesn't follow conventional design patterns of naming classes with "Proper" names (like StringList), and prefixing interfaces with an I.
It is also probably worth having a List rather than a string array as Ad.

Categories

Resources