C# Defining the Length of a Generic created using Reflection - c#

I have code like this:
Type typPrecise = MostPrecise(typeof(int), typeof(double));//Evaluates to double
var varGeneric = typeof(Number<>);
var varSpecific = varGeneric.MakeGenericType(typPrecise);
dynamic nmNumber = Activator.CreateInstance(varSpecific);
The nmNumber is of dynamic type and essentially produces a Generic Number. How do I then specify the number of items in Number.
I basically want to accomplish this but by using the dynamic code above:
Number<typPrecise> whatever = new Number<typPrecise>(10);
An answer using 4.0 concepts is welcome.

Call the overload of Activator.CreateInstance that accepts constructor arguments:
dynamic nmNumber = Activator.CreateInstance(varSpecific, new object[] { 10 });
Incidentally note that the List<T>(int) constructor sets the initial capacity of the List, not the initial number of items (Count). The initial Count is always 0.

Related

C# - F# interoperability, how to get result instead of FSharpFunc

I'm learning F# and would like to write simple F# library which can be consumed from C# application. It works as expected for trivial F# functions e.g.
let Square x = x * x
From C# I can consume it and get the expected value:
var sqaredNumber = MyFSharpLibrary.Square(5);
However when I use a Sequence / IEnumerable<T> as function parameter I got FSharpFunc object instead of the result.
Here is my function:
let FilterEvenNumbers input = Seq.filter(fun x -> x % 2 = 0)
And this is how I try to use it from C# code:
var numbers = new int[] { 1, 2, 3, 4 };
var filteredNumbers = MyFSharpLibrary.FilterEvenNumbers(numbers);
Instead of value filteredNumbers contains FSharpFunc object. I could use method Invoke on that object but would like to avoid extra complexity.
How can I achieve that ?
This is because your function declaration returns a function. If you enter it into dotnet fsi you'll see the signature:
val FilterEvenNumbers: input: 'a -> (seq<int> -> seq<int>)
See the parentheses? That means a single FSharpFunc object is returned, and it is the function that you call with input.
As you can see, input isn't passed to the filtering function, nor is its type associated at all with the inferred parameterized types for Seq.
To fix this, you need to pass input to Seq.filter.

Cannot compare object from Arraylist to the actual object

I'm trying to select a random user control within an array list. I get the index of the array but it tells me it cannot simply convert int to UserControl. Anyone knows what I did wrong?
ArrayList notiList = new ArrayList();
int count = 0;
int i;
public MainPage()
{
this.InitializeComponent();
foreach (NotiObject noti in itemsPanel.Children.Where(c => c is NotiObject))
{
notiList.Add(noti);
System.Diagnostics.Debug.WriteLine(noti);
}
i = new Random().Next(0, notiList.Count);
}
void sendNotification()
{
NotiObject randomNoti = notiList.IndexOf(i);
}
As Dai has hinted, ArrayList is a particularly old thing, from back in the days when .net was relatively new and didn't have the incredibly useful feature known as generics.
The manual page for ArrayList says this (my emphasis):
Important
We don't recommend that you use the ArrayList class for new development.
Instead, we recommend that you use the generic List class.
Even the manufacturer is saying "don't use this product"
The big problem with ArrayList is that because it wants to be able to store anything, it holds its contents in an object array
This means you can put two completely unrelated things in next to each other, you have to inspect the type of them if you do, and you always have to cast to turn the object back into what you want
notiList.Add(123); //whoops, that's not a NotiObject
foreach(var o in notiList)
var n = (NotiObject)notiList[0]; //whoops, that's a crash
}
So, working with it is pretty wearisome, particularly the part where you have to cast all the time.. This gets boring very quickly:
object o = "hello";
object p = "world";
object q = (string)o + (string)p;
object r = ((string)q).Substring(3).IndexOf((stribg)p);
r = (int)r + ((int)r)/2;
Storing everything in an object can be done, but look at what a mess it is. You'd have to start putting the type name into the variable name just to help remember that r was an int, and q was a string - Hungarian notation's another relic of the past.
When you put things in an ArrayList, this is what you're doing; storing them in object
So generics were invented and List was invented. A list that can be custom made to store a single type of objects like a string, int or NotiObject
var nums = new List<int>();
nums.Add(123); //works
var notiList = new List<NotiObject>();
notiList.Add(123); //compiler refuses this one
Now I've said all that, it's possible to answer your question. This code doesn't make sense:
NotiObject randomNoti = notiList.IndexOf(i);
i is an integer. IndexOf is a method that finds the numeric index of an item in the list. If the list was "a","b","c" and you asked for IndexOf("b") the result is 1 because b is at the second index, and indexing starts from 0.
IndexOf is not "get me the object at index blahblah", it's "tell me the index of this object blahblah"
The code doesn't make sense because you've passed an integer in and the list stores NotiObject. IndexOf will never find an integer in a list of NotiObject. This was the first mistake. You were allowed to make it because ArrayList stores everything as objects so you're allowed to pass an integer into IndexOf even if there are no integers in the list
IndexOf returns an integer. You cannot assign an integer to a variable of type NotiObject. This is the thing the compiler is complaining about
Even if you form the code correctly, you still have to cast:
NotiObject randomNoti = (NotiObject)notiList[i];
It's all very wearisome and if you persist with ArrayList probably not the last mistake you'll make with it either
If you used a List<NotiObject> you wouldn't have been allowed to pass an integer to IndexOf; the compiler would have stopped you which would hopefully then have made you assess IndexOf in the docs, and see that it's for finding the int index from the object, not the object at int index
You'd write code like:
List<NotiObject> notiList = new List<NotiList>();
...
NotiObject randomNoti = notiList[i];
without the cast. If you want to read more into why there is no cast, check out some introductory articles to generics. In a nutshell generics (any time you see something like <T> or <TBlahBlah>) allow you to specify something like a template code skeleton that the compiler uses to create code for you; code that substitutes the for the kind of object you want to work with. There isn't any casting any more because the compiler will write a whole List class that dedicatedly only works with NotiObjects

Methods for dynamically creating an array in C#

First, I don't have much experience in .Net - especially within the last 7 years.
I'm trying to develop an application and would to incorporate another library (https://github.com/Giorgi/Math-Expression-Evaluator)
That library allows me to evaluate math expressions like Evaluate("a+b", a: 1,b: 1). The method signature is public decimal Evaluate(string expression, object argument = null)
I would like to understand better how .Net translates comma-separated arguments into a single "argument".
I'm not sure how to create that argument dynamically.. for example, iterating through a list of values and creating an object that will match the appropriate argument for that signature.
I'm really just looking for pointers for documentation and more information.. Thanks for anything.
EDIT: Sorry.. purposely left it broad because I wasn't looking for people to do my work for me.. just can't seem to find a starting point to do my own research.
The method is called like
dynamic engine = new ExpressionEvaluator() ;
engine.Evaluate("(c+b)*a", a: 6, b: 4.5, c: 2.6)) ;
In the body of Evalute() is this code (which turns that argument into a Dictionary of String, Decimal pairs.
if (argument == null)
{
return new Dictionary<string, decimal>();
}
var argumentType = argument.GetType();
var properties = argumentType.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Where(p => p.CanRead && IsNumeric(p.PropertyType));
var arguments = properties.ToDictionary(property => property.Name,
property => Convert.ToDecimal(property.GetValue(argument, null)));
return arguments;
What I'd like to be able to do is parse a String like "a:1,b:2" and turn it into an object that matches that Evaluate() signature.
That library is using high level magic... Very high level :-)
The trick is that the class is declared as:
public class ExpressionEvaluator : DynamicObject
So it is a class that implements the dynamic magic introduced in .NET 4.0
Now... In the class there are two Evaluate methods:
public decimal Evaluate(string expression, object argument = null)
and
private decimal Evaluate(string expression, Dictionary<string, decimal> arguments)
The only method normally visible and usable is the first one. It is used like:
engine.Evaluate("a + b + c", new { a = 1, b = 2, c = 3 });
The new { ... } creates an anonymous object, that is then "unpacked" here through the use of reflection to a Dictionary<string, decimal> to be fed to the private Evaluate().
If you try to use the other notation, the one like:
engine.Evaluate("a + b + c", a: 1, b: 2, c: 3 });
then the .NET can't match the method to the public Evaluate() that is present, but the class, being a subclass of DynamicObject, causes the C# compiler to write some "magic" code that launches this method (that is still implemented by the ExpressionEvaluator):
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
That first checks that we want to call Evaluate:
if (nameof(Evaluate) != binder.Name)
and if we are trying to call Evaluate, it unpacks the parameters to a new Dictionary<string, decimal>() and then calls the private Evaluate().
As a sidenote, to use the "dynamic" way of writing Evaluate you have to declare the engine variable like;
dynamic dynamicEngine = new ExpressionEvaluator();
So using the dynamic variable type.
Now... As the library is written you can:
Use an anonymous object, with the problem that anonymous objects must have their "shape" defined at compile time (so at compile time you must know that you will need a a, a b and a c. You can't need a d at runtime if you didn't create a new { a, b, c, d } at compile time). See for example a response I gave three years ago about how to create dynamic anonymous types at runtime. One of the reasons I gave for that block of code was:
there are parts of the .NET framework that heavily use reflection to render objects (for example all the various datagrids). These parts are incompatible with dynamic objects and often don't support object[]. A solution is often to encapsulate the data in a DataTable... or you can use this :-)
Note that in one of the comments to that response there is a link to a modified version of my code used by one of the many implementations of Dynamic.Linq.
Use a non-anonymous object (a new Foo { a = 1, b = 2 c = 3 }). The library doesn't make distinctions between anonymous and non-anonymous objects. So same limitation as before, because at compile time you need a Foo class with the right number of parameters
Use the dynamic notation. Sadly even that is quite static. You can't easily add new parameters, that for the number and name of the "variables" must be defined at compile time.
A possible solution is to modify the source code (it is a single file) and make public this method:
private decimal Evaluate(string expression, Dictionary<string, decimal> arguments)
then you can easily and dynamically populate the Dictionary<string, decimal> arguments

Passing Argument To Method that Requires "ref System.Array"

I'm using a third party library. One of the methods requires passing an array via ref that will be populated with some info. Here's the definition for the method:
int GetPositionList(ref Array arrayPos)
How do I construct arrayPos so that this method will work? In the library's not so complete documentation it defines the method as such:
long GetPositionList(structSTIPosUpdate() arrayPos)
I've tried this but of course I'm getting errors:
System.Array position_list = new System.Array();
sti_position.GetPositionList(ref position_list);
Any ideas?
This is the Sterling Trader Pro ActiveX API, right? Did you create an Interop dll using tlbimp.exe? The GetPositionList API expects an array which will hold structs of type structSTIPositionUpdate. Normally an out modifier is used if the callee initializes the passed-in data, and ref if the data is to be initialized. According to the meaning of the API the modifier should be out, so that this should work:
structSTIPositionUpdate [] entries = new structSTIPositionUpdate[0]; // or null
num_entries_returned = GetPositionList(ref entries);
Alternatively, try creating an array of these structs which is big enough to hold the expected number of entries, then pass it to the function:
structSTIPositionUpdate [] entries = new structSTIPositionUpdate[100]; // say
num_entries_returned = GetPositionList(entries);
Update: If you are getting type mismatches with System.Array, try
System.Array entries = Array.CreateInstance(typeOf(structSTIPositionUpdate), N);
where N is the number of elements in the array.
To create an instance of an Array you can use the CreateInstance method:
Array a = Array.CreateInstance(typeof(Int32), 10);
GetPositionList(ref a);
The type, dimension and size of the array is something the library author should document. The GetPositionList may be badly designed and simply create a new Array for you essentially meaning that the library author should have used out instead of ref. In that case you can use a null array:
Array a = null;
GetPositionList(ref a);
You can use Array.CreateInstance
This may help you:
http://msdn.microsoft.com/en-us/library/szasx730%28VS.80%29.aspx
...although I don't understand why an object needs to have the "ref" keyword. Objects are passed by reference, so this should work anyway, without making use of the ref keyword. For arrays like int[] or string I understand this...
This works:
Array position_list = new int[]{1, 3, 5, 5,6};
sti_position.GetPositionList(ref position_list);
I also using Sterling Trader API. I use this code:
private structSTIPositionUpdate[] PositionList {
get {
Array arrayPos = null;
_position.GetPositionList(ref arrayPos);
return (structSTIPositionUpdate[]) arrayPos;
}
}

Need help converting C# to vb. "array initializer is missing 1 elements"

I am trying to convet the following code from C# to Vb using 3.5 framework.
Here is the code in C# that I am having trouble with.
MethodInfo mi = typeof(Page).GetMethod("LoadControl", new Type[2] { typeof(Type), typeof(object[]) });
I thought it would be like this in VB;
Dim mi As MethodInfo = GetType(Page).GetMethod("LoadControl", New Type(2) {GetType(Type), GetType(Object())})
but I am getting the following error "array initializer is missing 1 elements"
The other line that I am having trouble with and getting the same error is
control = (Control) mi.Invoke(this.Page, new object[2] { ucType, null });
I tried this in vb but it does not work.
control = DirectCast(mi.Invoke(Me.Page, New Object(2) {ucType, Nothing}), Control)
ucType is defined as follows
Dim ucType As Type = Type.[GetType](typeName(1), True, True)
Any help would be greatly appreciated.
VB.Net arrays are 0-based, but declared using the highest-index rather than the number of items. So a 10-item array, indexed 0..9, is declared as Item(9).
With that said, the real solution to your problem is to let the compiler figure out the array length, like so:
Dim mi As MethodInfo = GetType(Page).GetMethod("LoadControl", New Type() {GetType(Type), GetType(Object())})
In VB.NET the array declaration takes the upper bound of the array, not the length like C# does (kind of silly if you ask me). Because of this, you need to reduce the number passed into your array declarations by 1 (since arrays are zero-based).
For the first line you need to change new Type(2) into New Type(1).
Dim mi As MethodInfo = GetType(Page).GetMethod("LoadControl", New Type(1) {GetType(Type), GetType(Object())})
In VB.Net the number specified in the array initializer is the highest accessible index vs. the length. The second line you mentioned has the same problem and solution.
VB uses the upper bound as the argument for arrays.
new byte[X]
new byte(X) 'wrong, 1 more element
new byte(X-1) 'correct, kinda confusing
new byte(0 to X-1) 'correct, less confusing
I suggest using the (0 to X-1) style, because it's a lot clearer. It was a lot more important in the vb6 days when array(X) could mean 0 to X or 1 to X depending on the context.
It will be like this -
Dim mi As MethodInfo = GetType(Page).GetMethod("LoadControl", New Type(1) {GetType(Type), GetType(Object())})
The other one will be -
control = DirectCast(mi.Invoke(Me.Page, New Object(1) {ucType, Nothing}), Control)
There is an online version available at http://converter.telerik.com which converts
C# to VB and vice versa.

Categories

Resources