Add methods to dictionary for user selection - c#

Is it possible to add methods directly to a Dictionary? without having to use a more complex delegate solution. I get the error: "cannot convert to class.method".
I have a class with a number of methods, given a users input one of these methods should be selected:
Code:
class CTARules
{
public static void TwentyFiftyMA()
{
//do stuff
}
public static void TwentyHundredMA()
{
//do stuff
}
}
List<Data_Raw> myList = new List<Data_Raw>();
Dictionary<string, CTARules> rulesDictionary = new Dictionary<string, CTARules>(){ };
rulesDictionary.Add("twentyFifty", CTARules.TwentyFiftyMA());
rulesDictionary.Add("twentyHundred", CTARules.TwentyHundredMA());
The idea is of course that if the user selects the string which equals the key of the Dictionary, I can easily fetch the corresponding method to run.
Also, why can't I create my dictionary at class level?
EDIT:
I changed the methods to be called to:
public static List<Data_Result> TwentyFiftyMA(List<Data_Raw> myRawData)
{
List<Data_Result> ResultList = new List<Data_Result>();
//do stuff with lists
return ResultList;
}
public static List<Data_Result> TwentyHundredMA(List<Data_Raw> myRawData)
{
List<Data_Result> ResultList = new List<Data_Result>();
return ResultList;
}
I still get the error: Argument 2: cannot convert from 'method group' to 'Action'. The methods must be able to receive (a) parameters, they can be void methods - same error.

Your methods are convertible to Action delegate, so you can use:
Dictionary<string, Action> rulesDictionary
While adding methods, do not call them, that will return the result of the method, you can use method groups:
rulesDictionary.Add("twentyFifty", CTARules.TwentyFiftyMA);
And why can't I create my dictionary at class level?
Because all executable code should be inside of a method. The declarations inside a class are just metadata, not executable code. You can initialize fields in the class level but that's just a syntactic sugar, the compiler emits the code to the class's constructor.

Related

How to loop thru a Generic Class / List

Hi I'm learning Generics thru MSDN here
and I want to do a foreach loop to display data in a console.writeline.
I tried to do the foreach loop as below but it's not working.
// Declare the generic class.
public class GenericList<T>
{
public void Add(T input) { }
}
class TestGenericList
{
private class ExampleClass { }
static void Main()
{
// Declare a list of type int.
GenericList<int> list1 = new GenericList<int>();
list1.Add(150);
// Declare a list of type string.
GenericList<string> list2 = new GenericList<string>();
list2.Add("Toyota");
// Declare a list of type ExampleClass.
GenericList<ExampleClass> list3 = new GenericList<ExampleClass>();
list3.Add(new ExampleClass());
}
}
foreach (GenericList<T> item in list2.ToString().ToList())
{
Console.WriteLine(item); // NOT WORKING !!!!
}
Firstly, by calling the method ToString() on list2, you will get the name of type of your object, because you didn't create your own implementation of method ToString(). So, you are trying to enumerate through letters of string "AppName.GenericList". Unfortunately, letters are of type 'char' and not GenericList.
Secondly, there is no backend behind method Add - items you are 'adding' to your list, in reality aren't added anywhere. Method public void Add(T input) { } does nothing (you should fill the brackets). GenericList at this stage stores no data.
Thirdly, you can't enumerate through your GenericList, because you didn't implement the method GetEnumerator. Only then you will be able to use keyword foreach on objects of your type.
Many of this issues will be solved by the end of the tutorial from link that you provided.

List instance does not recognized in method context in C#

I am trying to understand why compiler throws an error when I try to use "List" specific method "Add" in this context. The error explanation states that it is because of the field definition. (IEnumerable does not include "Add" method) However, I newed it in inner context. I will be grateful for a reasonable explanation.
Note: I know that is because IEnumerable is an interface and I can use IList instead. However, what I could not understand is that compiler should extract the type in inner context but its not.
class Program
{
private static IEnumerable<string> exampleList;
public static void Main()
{
exampleList = new List<string>();
exampleList.Add("ex"); // ==> Compiler Error Here.
}
}
Your exampleList is defined as an IEnumerable<string>, so its compile-time type is an IEnumerable<string>. Therefore, when the compiler is compiling the code, it can only know that it is an IEnumerable<string>.
Two main fixes exist:
1) Declare exampleList as an IList
private static IList<string> exampleList;
2) Use a temporary variable to set the list contents.
public static void Main()
{
var list = new List<string>();
list.Add("ex");
exampleList = list;
}
Just to briefly explain why the compiler can only know that it is an IEnumerable, consider the following code:
IEnumerable<string> exampleList;
if (TodayIsAWednesday())
{
exampleList = new List<string>();
}
else
{
exampleList = new string[0];
}
// How can the compiler know that exampleList is a List<string>?
// It can't!
exampleList.Add("ex");
Change your code as below, will solve the problem.
private static List<string> exampleList;
or change your code in static Main as below
var newCollection = exampleList.ToList();
newCollection.Add("ex"); //is your new collection with the item added
As you see,"I" meant it is a Interface.It can accept all kind of Enumerable,but have not Add's Method.
You can see:https://msdn.microsoft.com/en-us//library/system.collections.ienumerable(v=vs.110).aspx

How can i cast from Func<Object> to Func<dynamicType> c#

Hello this is my first post, don't be to hard if I do anything wrong :D
I am writing a DeSerializer for a big Programm,
To do so, I have a own Class
public class DeSerializeableElement
{
public Func<Object> action;
public Type type;
public DeSerializeableElement( Func<Object> p_action,Type p_type)
{
type = p_type;
action = p_action;
}
I read a String and then it always starts with 0XXX a 4 digit number.
with this number I get the right method from my
Dictionary<int,DeSerializableElement>
the initialize of the Dictionary is auto Generated and has 300 elements
deSerializableObjectDictionary.Add(276, new DeSerializeableElement(GetString, typeof(System.String)));
GetString is a method with no parameters and returns a String
Now my problem, if I Deserialize a List, at the moment I create a DeSerializableElement the Func looses its return value Information. Because I save it as Func so I get back a List
but it`s Important to get a List in case of GetString
there are also GetInt or GetDouble and lots more
So If i call GetList(GetString) I want as return value a List
and if I call GetList(GetInt) I want a List and so on.
But I get always a List because my SerializableElement has Func as attribute
The call for GetList looks like
GetList(deSerializableObjectDictionary[objectIdent].action);
GetList looks like
public IList<T> GetList<T>(Func<T> p_action) //T is always Object because of Func<Object> here I the right Type
{
IList<T> list = new List<T>();
ExpectToken('['); //The start Token of a serialized List
while (!IsNextToken(']')) //End Token of serialized List
{
list.Add(p_action());
}
return lst;
}
Any road you choose, it will one such that you are losing type safety. For example, you can defer to a Dictionary<int, object> and wrap that with a GetList<T> method where T is the actual type you want. A mis-use of this method can lead to runtime exceptions.
An example would be:
void Main()
{
var idToFunc = new Dictionary<int, object>();
idToFunc.Add(1, new DeSerializeableElement<int>(() => 1));
Console.WriteLine(GetList<int>(((DeSerializeableElement<int>) idToFunc[1]).Func));
}
public class DeSerializeableElement<T>
{
public Func<T> Func { get; set; }
public DeSerializeableElement(Func<T> func)
{
Func = func;
}
}
I would definitely of the risks involved with this kind of code. Although possible, I would advise you to re-think what you're doing and the architecture of your deserializer.

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

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

Using a class derived from generic list with LINQ

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

Categories

Resources