C# enums as function parameters? - c#

Can you pass a standard c# enum as a parameter?
For example:
enum e1
{
//...
}
enum e2
{
//...
}
public void test()
{
myFunc( e1 );
myFunc( e2 );
}
public void myFunc( Enum e )
{
// Iterate through all the values in e
}
By doing this I hope to retrieve all the names within any given enum. What would the Iteration code look like?

This!
public void Foo(Enum e)
{
var names = Enum.GetNames(e.GetType());
foreach (var name in names)
{
// do something!
}
}
EDIT: My bad, you did say iterate.
Note: I know I could just do the GetNames() call in my foreach statement, but I prefer to assign that type of thing to a method call first, as it's handy for debugging.

Use the Enum.GetNames( typeof(e) ) method, this will return an array of strings with the names.
You can also use Enum.GetValues to obtain the counterpart values.
Edit -Whoops - if you are passing the parameter as Enum, you will need to use e.GetType() instead of typeof() which you would use if you had passed the parameter in as the actual Enum type name.

You mean something like Enum.GetNames?

Enum.GetValues
Enum.GetNames
so something like...
foreach(e1 value in Enum.GetValues(typeof(e1)))

You will have trouble if you try passing an enum directly to myFunc, as in the following example:
enum e1 {something, other};
myFunc(e1); // Syntax error: "e1 is a type, but is being used like a variable"

Like this:
public void myFunc(Enum e)
{
foreach (var name in Enum.GetNames(typeof(e)))
{
Console.WriteLine(name);
}
}

correct is:
public void myFunc(Enum e)
{
foreach (var name in Enum.GetNames(e.GetTye()))
{
Console.WriteLine(name);
}
}

Related

C# : Is there a way to pass an enum as an argument?

I've searched (maybe not enough) but couldn't find an answer.
I want to make a generic function where I can pass any enum to use with a CheckedListBox (get or set the value).
public enum TypeFlags
{
None = 0x0,
//List of flag
}
private void makeFlagOrBitmask(CheckedListBox list, Type e)
{
int myFlags = 0x0;
//I want to achieve something like that
foreach (Object item in list.CheckedItems)
{
//(TypeFlags)Enum.Parse(typeof(TypeFlags), item);
//So e should be the enum himself, but i can't figure how to do that
myFlags += (int)((e)Enum.Parse(typeof(e), item.tostring()));
}
}
So, I can make/read any flags with a single function.
The problem is that I can't figure out how to pass the enum as I need it in the function.
might not be complete but it sounds like you need a generic Enum iterator. I picked up the below code from Create Generic method constraining T to an Enum
public T GetEnumFromString<T>(string value) where T : struct, IConvertible
{
if (!typeof(T).IsEnum)
{
throw new ArgumentException("T must be an enumerated type");
}
//...
}
I know this is not a nice Code but this works for me:
If the method want an object instead of a type (maybe you can do this with a type) you can do it like this:
if (e.GetType() == typeof(ImageType))
{
ValueArray = GetEnumArray(ImageType.Bmg);
}
This way you can check what Enum it es before you do something.
I hope this can help you.
You want to change this line:
myFlags += (int)((e)Enum.Parse(typeof(e), item.tostring()));
Into this:
myFlags += (int)((e)Enum.Parse(e, item.tostring()));
Since e is already a type. As of how to pass the parameter:
makeFlagOrBitmask(myCheckBoxList, typeof(myEnum));
I hope this helps.
EDIT:
To make sure only enums will work, add this to the top of your function:
if (!e.IsEnum)
return;

How to pass anonymous types as parameters?

How can I pass anonymous types as parameters to other functions? Consider this example:
var query = from employee in employees select new { Name = employee.Name, Id = employee.Id };
LogEmployees(query);
The variable query here doesn't have strong type. How should I define my LogEmployees function to accept it?
public void LogEmployees (? list)
{
foreach (? item in list)
{
}
}
In other words, what should I use instead of ? marks.
I think you should make a class for this anonymous type. That'd be the most sensible thing to do in my opinion. But if you really don't want to, you could use dynamics:
public void LogEmployees (IEnumerable<dynamic> list)
{
foreach (dynamic item in list)
{
string name = item.Name;
int id = item.Id;
}
}
Note that this is not strongly typed, so if, for example, Name changes to EmployeeName, you won't know there's a problem until runtime.
You can do it like this:
public void LogEmployees<T>(List<T> list) // Or IEnumerable<T> list
{
foreach (T item in list)
{
}
}
... but you won't get to do much with each item. You could call ToString, but you won't be able to use (say) Name and Id directly.
Unfortunately, what you're trying to do is impossible. Under the hood, the query variable is typed to be an IEnumerable of an anonymous type. Anonymous type names cannot be represented in user code hence there is no way to make them an input parameter to a function.
Your best bet is to create a type and use that as the return from the query and then pass it into the function. For example,
struct Data {
public string ColumnName;
}
var query = (from name in some.Table
select new Data { ColumnName = name });
MethodOp(query);
...
MethodOp(IEnumerable<Data> enumerable);
In this case though, you are only selecting a single field, so it may be easier to just select the field directly. This will cause the query to be typed as an IEnumerable of the field type. In this case, column name.
var query = (from name in some.Table select name); // IEnumerable<string>
You can't pass an anonymous type to a non generic function, unless the parameter type is object.
public void LogEmployees (object obj)
{
var list = obj as IEnumerable();
if (list == null)
return;
foreach (var item in list)
{
}
}
Anonymous types are intended for short term usage within a method.
From MSDN - Anonymous Types:
You cannot declare a field, a property, an event, or the return type of a method as having an anonymous type. Similarly, you cannot declare a formal parameter of a method, property, constructor, or indexer as having an anonymous type. To pass an anonymous type, or a collection that contains anonymous types, as an argument to a method, you can declare the parameter as type object. However, doing this defeats the purpose of strong typing.
(emphasis mine)
Update
You can use generics to achieve what you want:
public void LogEmployees<T>(IEnumerable<T> list)
{
foreach (T item in list)
{
}
}
"dynamic" can also be used for this purpose.
var anonymousType = new { Id = 1, Name = "A" };
var anonymousTypes = new[] { new { Id = 1, Name = "A" }, new { Id = 2, Name = "B" };
private void DisplayAnonymousType(dynamic anonymousType)
{
}
private void DisplayAnonymousTypes(IEnumerable<dynamic> anonymousTypes)
{
foreach (var info in anonymousTypes)
{
}
}
Normally, you do this with generics, for example:
MapEntToObj<T>(IQueryable<T> query) {...}
The compiler should then infer the T when you call MapEntToObj(query). Not quite sure what you want to do inside the method, so I can't tell whether this is useful... the problem is that inside MapEntToObj you still can't name the T - you can either:
call other generic methods with T
use reflection on T to do things
but other than that, it is quite hard to manipulate anonymous types - not least because they are immutable ;-p
Another trick (when extracting data) is to also pass a selector - i.e. something like:
Foo<TSource, TValue>(IEnumerable<TSource> source,
Func<TSource,string> name) {
foreach(TSource item in source) Console.WriteLine(name(item));
}
...
Foo(query, x=>x.Title);
You can use generics with the following trick (casting to anonymous type):
public void LogEmployees<T>(IEnumerable<T> list)
{
foreach (T item in list)
{
var typedItem = Cast(item, new { Name = "", Id = 0 });
// now you can use typedItem.Name, etc.
}
}
static T Cast<T>(object obj, T type)
{
return (T)obj;
}
Instead of passing an anonymous type, pass a List of a dynamic type:
var dynamicResult = anonymousQueryResult.ToList<dynamic>();
Method signature: DoSomething(List<dynamic> _dynamicResult)
Call method: DoSomething(dynamicResult);
done.
Thanks to Petar Ivanov!
To pass anonymous types around, consider using dynamic. A longer example is shown below and the technique you can use. For example, consider calling the TreadSafeDynamicObject here 'CustomEmployee' to make more sense of the code. The code has a constructor that accepts a dynamic object (your anonymous, potentially nested class), for example :
var someCustomEmploye = new {
IsIntern = false,
EmployeeFacts = new {
IsSenior = true,
BirthDate = new DateTime(1960, 1, 1)
}
};
You can transform someCustomEmployee to a dynamic object using the technique shown below, for example pass in 'someCustomEmployee' into the constructor, in my code it would be:
dynamic someEmp = new ThreadSafeDynamicObject(someCustomEmployee);
Once you have transformed someEmp into a proper dynamic object, your LogEmployee function can for example serialize the object and log it or handle it in some other way (note that you do not have to go via converting it to a dynamic object anyways, if it is enough to just serialize the anonymous class instance).
Example :
dynamic threadSafeToyota = new ThreadSafeDynamicObject(new {
Make = "Toyota",
Model = "CR-H",
Propulsion = new {
IsHybrid = true,
UsesPetrol = true,
ElectricMotor = true
}
});
The code accepts a dynamic object and uses a private method 'ToDictionary' to convert the object graph of the anonymous class instance provided as an alternative way to set properties on the dynamic object.
Note that I also have added some more code here to provide thread safety when setting and getting properties.
public class ThreadSafeDynamicObject : DynamicObject, IEnumerable<KeyValuePair<string, object>>
{
public ThreadSafeDynamicObject()
{
}
public ThreadSafeDynamicObject(dynamic members)
{
var membersDict = ToDictionary(members);
InitMembers(membersDict);
}
private IDictionary<string, object> ToDictionary(object data)
{
var attr = BindingFlags.Public | BindingFlags.Instance;
var dict = new Dictionary<string, object>();
foreach (var property in data.GetType().GetProperties(attr))
{
if (property.CanRead)
{
dict.Add(property.Name, property.GetValue(data, null));
}
}
return dict;
}
private void InitMembers(IDictionary<string, object> membersDict)
{
foreach (KeyValuePair<string, object> member in membersDict){
_members.AddOrUpdate(member.Key, member.Value, (key, oldValue) => member.Value);
}
}
private readonly ConcurrentDictionary<string, object> _members = new();
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
return _members.TryGetValue(binder.Name, out result);
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
_members.AddOrUpdate(binder.Name, value, (key, oldvalue) => value);
return true;
}
public override IEnumerable<string> GetDynamicMemberNames()
{
return _members.Keys.ToList().AsReadOnly();
}
public override string ToString()
{
return JsonSerializer.Serialize(_members);
}
public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
{
return _members.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return _members.GetEnumerator();
}
}
When running the code inside Linqpad 7 I got this output (I am using static System.Console and using System.Dynamic here):
WriteLine(threadSafe.ToString());
WriteLine(threadSafe.Make);
WriteLine(threadSafe.Model);
WriteLine(threadSafe.Propulsion.IsHybrid);
WriteLine(threadSafe.Propulsion.UsesPetrol);
WriteLine(threadSafe.Propulsion.ElectricMotor);
There are several advantages to this. It supports nested levels as you can see in the output and is very flexible. The method 'ToDictionary' is essential here. Also, we do not have to use additional libraries outside the .net framework, so the funtionality is built in. I have not checked all variants of this code, at least it supports the typical scenarios of anonymous type object graphs.
Key thing here is to transform your anonymous type first into a dictionary and then populate the internal concurrent dictionary with the members ('fields' or 'props') of the derived DynamicObject.
There are several ways to solve this :
You could do boxing. E.g. have a method that accepts object and use reflection to extract the properties and log the properties and their values
E.g. :
public void LogEmployees(object someCustomEmployee) { // .. }
You could transform the anonymous object into a dynamic object as shown in my sample
In addition to boxing or converting into a dynamic object, you could avoid reflection by serializing the converted object (either boxed object or dynamic variant).
If you know, that your results implements a certain interface you could use the interface as datatype:
public void LogEmployees<T>(IEnumerable<T> list)
{
foreach (T item in list)
{
}
}
I would use IEnumerable<object> as type for the argument. However not a great gain for the unavoidable explicit cast.
Cheers

C# - declare method in argument (delegate)

In the code below I pass method B as an action to be perfomed on on the objects in the IterateObjects method.
I would like to ask whether I can explicitly declare the method in the argument instead of passing it by name, something like this:
a.IterateObjects(delegate void(string s){//method body}) Its not correct but I am sure I have seen something like that working. Could you please advise? Thank you
DelTest a = new DelTest(); //class with method IterateObjects
a.IterateObjects(B) //HERE
private void B(string a)
{
listBox1.Items.Add(a);
}
//another class ....
public void IterateObjects(Action<string> akce)
{
foreach(string a in list)
{
akce(a);
}
}
Yes you can use a lambda like so :
a.IterateObjects ( x => listBox1.Items.Add(x) );
delegate void MyFunctionDelegate(string a);
public void Main()
{
iterateObjects (delegate(string a){/*do something*/});
}
public void IterateObjects(MyFunctionDelegate akce)
{
foreach(string a in list)
{
akce(a);
}
}
http://msdn.microsoft.com/en-us/library/900fyy8e%28VS.80%29.aspx
that's it :)
You can declare function B as anonymous function at the point of calling, through a lambda expression.
You can use a lambda expression:
a.IterateObjects((string s) => listBox1.Items.Add(s))

Declaring the type for a templatized function in C#

In c# it's possible to create a list of functions like so:
var myList = new List< Func<Foo> >();
This will allow functions (delegates) that take no arguments and return a value of type Foo to be added to the list. So something like:
Foo myFunc1() { ... }
would be a valid member of that list. My question is, how do I declare the type for a templatized function? How can I construct a List<> that will hold functions of the form:
T myFunc2<T>() { ... }
You need to do that inside a templatized class or method. Then you can refer to the generic type T just as you would refer to the specific type Foo.
In other words:
public class FuncContainer<T>
{
private List<Func<T>> list = new List<Func<T>>();
public void Fill()
{
// Initialize list
}
}
I think the other answers so far have misunderstood the problem... and I don't think you can actually do it, if I've read it correctly. Am I right in saying you'd like to be able to write this:
List<???> list = new List<???>(); // This line won't work
list.Add(Method1);
list.Add(Method2);
...
static int Method1() { ... }
static string Method2() { ... }
If I've misunderstood, and a simple generic type parameter of T in your method or class suffices, I'll delete this answer :)
The closest you could come to the above would be something like this:
public class FuncList
{
private readonly List<Delegate> list = new List<Delegate>();
public void Add<T>(Func<T> func)
{
list.Add(func);
}
}
You'd then use it as:
FuncList list = new FuncList();
list.Add<int>(Method1);
list.Add<string>(Method2);
Quite what you'd do with the list afterwards is tricky... what did you have in mind?
Yes this first signature is completely valid.
The signature of the last function you suggested is the following
List<Func<T>> x;
This holds a list of delegates which take no arguments and produce a T value.

Anonymous type as method parameter

My first try to use anonymous types(test):
private void button4_Click(object sender, EventArgs e)
{
test(new { a = "asd" });
}
private void test(string a)
{
}
I get an error "cannot convert from 'AnonymousType#1' to 'string' "
Also I'd like to know how to pass an anonymous type if the parameter is a string[]
private void test(string[] a)
{
}
Thanks in advance!
Something about your design is faulty. If your test function accepts only strings, then you can never pass an anonymous type to it, just as you can't pass an int, object, or any other non-string type.
a is a string property on your anonymous type
private void button4_Click(object sender, EventArgs e)
{
test((new { a = "asd" }).a);
}
private void test(string a)
{
}
Edit: Anonymous types do not derive from anything other than object so you cannot create a method that expects an anonymous type parameter.
Edit 2: when you create an anonymous type the compiler create an entirely new type based on the properties you set and the order in which they appear. You cannot create an anonymous type and use it in place of any other type (other than object). The most common scenario I've used them in is for binding when you need to flatten your object graph.
warning, I am horrible at coming up with good example scenarios and this is all from memory!
for example if I had a list of Person objects that had a name property and an address property that contained the street address and needed to bind to a list box
var people = new List<Person>()
listbox.TextMember = "Text";
listbox.ValueMember = "Value"
listbox.DataSource = from p in people
select new { Text = p.Name, Value = p.Address.StreetAddress };
There is no clean way to pass an anonymous type between methods; you're not meant to do it. Create a real type instead.
If you really really want to do this, you can use a helper method to fake it awkwardly by creating another "template" of that type to cast to later; see this and many similar articles.
EDIT: On closer examination, you don't appear to understand what an anonymous type actually is, so I suggest you take the other answers.
Just stumbled upon this outdated question and thought somebody here should mention possibility to use dynamic starting with C# 4.0 which is perfect for working with anonymous types. I.e. the code could be looking like this:
private void button4_Click(object sender, EventArgs e)
{
test(new { a = "asd" });
}
private void test(dynamic obj)
{
Console.WriteLine(obj.a);
}
This is bad, but it works ...
namespace AnonType
{
class Program
{
static void Main(string[] args)
{
var foo = new { a = "123", b = "abc" };
Anon(foo);
Console.ReadLine();
}
public static void Anon(object o)
{
Console.WriteLine(o);
}
}
}

Categories