Cannot deconstruct dynamic object while calling dll's method - c#

Say I have some dll with a method like so:
public (string, List<string>) MyMethod(NameValueCollection Settings, MyClass1 params)
{
//do something
return (result, errorList);
}
Now from my main project I will call it like so:
var shipmentNumber = string.Empty;
var errorList = new List<string>;
var DLL = Assembly.LoadFile($#"{AppDomain.CurrentDomain.BaseDirectory}{appSettings[$"{parameters.TestCase}_DLL_Name"]}");
Type classType;
classType = DLL.GetType($"{appSettings[$"{parameters.TestCase}_DLL_Name"].Replace(".dll", "")}.MyService");
dynamic d = Activator.CreateInstance(classType);
(result, errorList)= d.MyMethod(appSettings, params);
However this gives me an error on the last line shown here Cannot deconstruct dynamic objects. Is there a way I could return tuple properly here?

As per the compiler error message, you can't use deconstruction with dynamic values.
In this case you know that your method is going to return a tuple, so either cast the result to that:
(result, errorList) = ((string, List<string>)) d.MyMethod(appSettings, params);
Or assign to a tuple and then deconstruct:
(string, List<string>) tuple = d.MyMethod(appSettings, params);
(result, errorList) = tuple;
Note that the casting looks a bit funky with the double parentheses, but they're necessary: the outer parentheses are for casting syntax; the inner parentheses are for tuple type syntax.
Here's a complete simple example:
using System;
class Test
{
static void Main()
{
dynamic d = new Test();
// Variables we want to deconstruct into
string text;
int number;
// Approach 1: Casting
(text, number) = ((string, int)) d.Method();
// Approach 2: Assign to a tuple variable first
(string, int) tuple = d.Method();
(text, number) = tuple;
}
public (string, int) Method() => ("text", 5);
}

Related

Trying to map "similar looking" tuples returned from multiple functions to one variable

Say there is a library with code of this form:
public class SomeLib
{
public (bool WasOk, string Message) DoCheck(string fileName)
{
// do something here to check the file.
return (true, "all good");
}
public (bool WasOk, string Message) DoCheck(byte[] fileBytes)
{
// do something here to check the file as bytes
return (true, "all good");
}
}
The code which uses this library looks of this form:
int option = 1;
SomeLib lib = new SomeLib();
if (option == 0)
{
var res1 = lib.DoCheck("hello");
MessageBox.Show(res1.WasOk + res1.Message);
}
else
{
var res2 = lib.DoCheck(new byte[] { });
MessageBox.Show(res2.WasOk + res2.Message);
}
What I was hoping to do, was to store the returned value from the two calls to DoCheck, to a common variable. e.g.:
int option = 1;
SomeLib lib = new SomeLib();
var res; // doesn't compile, obviously
if (option == 0)
{
res = lib.DoCheck("hello");
}
else
{
res = lib.DoCheck(new byte[] { });
}
MessageBox.Show(res.WasOk + res.Message); // act on the result in the same way for both branches.
I hope this makes sense. Is what I am trying to do possible? Let's say that the code in the library cannot be changed.
var res doesn't compile because it doesn't have any type information. If you're making a statement that declares a variable the compiler has to be able to work out the type somehow, either from the left or the right side:
StringBuilder sb = new StringBuilder(); //both sides, available from the dawn of time
var sb = new StringBuilder(); //for a long time
StringBuilder sb = new(); //more recently
If there isn't a right side then the left side has to have the type info:
StringBuilder sb;
Thus for your case you need to put the type info on the left. You can even rename the members (but you don't have to)
(bool AllGood, string Note) res;
(bool WasOk, string Message) res;
(bool, string) res; //access the bool in res.Item1, string in res.Item2
You could do it in a one with a ternary:
var res = (option == 0) ? lib.DoCheck(hello) : lib.DoCheck(new byte[] { });
Both your methods return tuples with the same named members so your res will have res.WasOk and res.Message so it's compiled as if it's this:
(bool WasOk, string Message) res = ...
If your tuples coming out your methods had different names it would still compile as if it was this:
(bool, string) res = ...
And you could still access the data via Item1 and Item2
If you're doing this ternary approach then you could deconstruct the tuple too, which also allows you to rename:
var(allGood, note) = ... ? ... : ... ;
MessageBox.Show(note);
Instead of one tuple variable where you say res.Whatever, this has created two variables like as if you'd done this:
var res = ... ? ... : ... ;
var allGood = res.WasOk;
var note = res.Message;
Plenty of options for dealing with tuples..
Implicitly typed locals must be initialized
An implicitly typed local variable must be initialized with a value at the same time that it is declared. here
To correct this error
Assign a value to the variable or else give it an explicit type.
(bool AllGood, string Note) res;

Parse Strings to type in generic

I have the following method:
public static IQueryable<T> Where<T, P>(this IQueryable<T> source, Func<T, P> predicate, String filter) {
String[] values = _service.GetValues(filter);
}
The variable values is something like:
String[] values = { "1", "2", "C" };
I need to parse all values to the same type of P. So if P is of type int then it would fail because I would not be able to parse C to int. But if P would be of type String then it would pass since all 3 values can be parsed to String.
The types of P would be the basic ones: int, datetime, float, double, string, boolean ...
How to do this?
You could create a new method to do the conversion for you.
public IEnumerable<P> Parse<P>(string[] values) where P : IConvertable // Add constraint for some compile time notification errors
{
foreach (var value in values)
{
yield return (P)Convert.ChangeType(value, typeof(P));
}
}
Another option if you didn't want a new method would be to use this line.
var convertedValues = values.Select(value => (P)Convert.ChangeType(value, typeof(P)));
On the one line option if you add a .ToList() to the end it will do all the conversions at the line of assignment so it will cause the exception to be thrown immediately.
var convertedValues = values.Select(value => (P)Convert.ChangeType(value, typeof(P))).ToList();

IEnumerable to array of T[]

Perhaps the question title is incorrect. I have the following variables
IEnumerable x = // some IEnumerable
System.Type y = // some type
How can iterate over x in order to generate an array with items of type y?
When I look into the internet I found:
public T[] PerformQuery<T>(IEnumerable q)
{
T[] array = q.Cast<T>().ToArray();
return array;
}
Note I cannot call that method PerformQuery becuase y is of type System.Type in other words calling it as PerformQuery<typeof(y)>(x); or PerformQuery<y>(x); will give me a compiler error.
edit
Here is the reason why I have that problem. I have web service where I post to it two things. The type of table I will like to query (example typeof(Customer)), and the actual string query example "Select * from customers"
protected void Page_Load(object sender, EventArgs e)
{
// code to deserialize posted data
Type table = // implement that here
String query = // the query that was posted
// note DB is of type DbContext
IEnumerable q = Db.Database.SqlQuery(table, query );
// here I will like to cast q to an array of items of type table!
You can use Expression Trees:
public static class MyExtensions
{
public static Array ToArray(this IEnumerable source, Type type)
{
var param = Expression.Parameter(typeof(IEnumerable), "source");
var cast = Expression.Call(typeof(Enumerable), "Cast", new[] { type }, param);
var toArray = Expression.Call(typeof(Enumerable), "ToArray", new[] { type }, cast);
var lambda = Expression.Lambda<Func<IEnumerable, Array>>(toArray, param).Compile();
return lambda(source);
}
}
It generates x => x.Cast<Type>().ToArray() for you, with Type known at runtime.
Usage:
IEnumerable input = Enumerable.Repeat("test", 10);
Type type = typeof(string);
Array result = input.ToArray(type);
var ObjectsOfType_y = x.OfType<object>().Where(x => x.GetType() == y);
Notice that this will return an IEnumerable<object>, though. There's no way around that because the type that y (Type) represents is unknown at compile time.
According to my understanding, IENumerable contains only one type. If I understand what you're trying to do, IENumerable already only contains only objects of type y. If y needs to change, you can write an extension method:
public static T[] ToArray<T>(this IEnumerable<T> source)
{
int length = System.Linq.Enumerable.Count(source);
T[] newArray = new T[length];
int i = 0;
foreach(T item in source)
{
newArray[i] = item;
}
return newArray;
}

Create a lambda expression with a new anonymous type at runtime

I want to invoke a method that expects a parameter like this:
Expression<Func<sometype, 'a>> expr
I need to construct this parameter at runtime, because I won't know what the anonymous type will look like before; it could have any amount of fields:
x => new { a=x.a, b=x.b, c=x.c, etc... }
I can create a type at runtime that has the same 'signature' (Is that the correct word for this?) as the desired anonymous type, but the question is: How do I construct this lambda expression at runtime from that? Especially Expression.New is bugging me, because I need to pass a constructorInfo to it that I have to get from an existing type (which can indeed be an anonymous type, but I can't create an anonymous type at runtime. Or is there a way to do that?).
Update (some context as requested in the comments)
The method I want to invoke is:
DependentNavigationPropertyConfiguration.HasForeignKey<TKey>(Expression<Func<TDependentEntityType, TKey>> foreignKeyExpression)
The reason I want to do this is to automatically make a navigation property to an entity that inherits from a certain base class include the key of that base class in the foreign key. Because an entity can have multiple key fields of any type, the type TKey is only known to me at runtime.
Use a separate method:
public static void Main()
{
var myExpression = Express(str => new {
String = str,
Length = str.Length
});
// We can compile/use it as well...
var compiledExpression = myExpression.Compile();
var anonymousOutput = compiledExpression("Input String");
Console.WriteLine(anonymousOutput.String); // Output: Input String
Console.WriteLine(anonymousOutput.Length); // Output: 12
Debug.WriteLine(myExpression); // Output: "str => new <>f__AnonymousType0`2(String = str, Length = str.Length)"
Console.ReadLine();
}
static Expression<Func<String, T>> Express<T>(Expression<Func<String, T>> expression)
{
return expression;
}
Note however, that the starting type (in my example String) must be known up front.
Update:
Since what it sounds like you're trying to do is dynamically create a type, I'll give you a simple example of how to do that.
public static void Main()
{
// Create an anonymous type with two fields
Type myAnonymousType = CreateNewType<String, Int32>();
dynamic myAnon = Activator.CreateInstance(myAnonymousType);
myAnon.FieldA = "A String";
myAnon.FieldB = 1234;
Console.WriteLine(myAnon.FieldA); // Output : "AString"
Console.WriteLine(myAnon.FieldB); // Output : 1234
Console.ReadLine();
}
public static Type CreateNewType<TFieldTypeA, TFieldTypeB>()
{
// Let's start by creating a new assembly
AssemblyName dynamicAssemblyName = new AssemblyName("MyAsm");
AssemblyBuilder dynamicAssembly = AssemblyBuilder.DefineDynamicAssembly(dynamicAssemblyName, AssemblyBuilderAccess.Run);
ModuleBuilder dynamicModule = dynamicAssembly.DefineDynamicModule("MyAsm");
// Now let's build a new type
TypeBuilder dynamicAnonymousType = dynamicModule.DefineType("MyAnon", TypeAttributes.Public);
// Let's add some fields to the type.
FieldInfo dynamicFieldA = dynamicAnonymousType.DefineField("FieldA", typeof(TFieldTypeA), FieldAttributes.Public);
FieldInfo dynamicFieldB = dynamicAnonymousType.DefineField("FieldB", typeof(TFieldTypeB), FieldAttributes.Public);
// Return the type to the caller
return dynamicAnonymousType.CreateType();
}
As you can see, this is a little more complicated. If you want to study the topic further though, definitely reference Reflection.Emit.
Anonymous types are a compiler feature. If you don't get the compiler to create them at compile-time, then you will have to use meta-programming - either TypeBuilder or maybe CSharpCodeProvider. You might be better off using tuples - at least they are easy to create (you can use Tuple.Create easily enough).
As for the expression; I would suggest typing it as Expression<Func<sometype, object>> - which will work for any formulation. The code inspecting the Expression can of course see what the actual type is.
you can do simply like this
context.Students.Join(context.Courses, a => a.Course_id, b => b.Course_id, (a, b) => new { Student= a, Course= b }).Where(x => x.Student_id == studentId)
.Select(y => new
{
StudentId = y.Student.StudentId,
RegistrationNumber = y.Student.RegNo,
Name = y.Student.Name,
Coursename = y.Course.Name
}).ToList();

How do I convert IEnumerable<T> to string, recursively?

I want a function that I can call as an alternative to .ToString(), that will show the contents of collections.
I've tried this:
public static string dump(Object o) {
if (o == null) return "null";
return o.ToString();
}
public static string dump<K, V>(KeyValuePair<K, V> kv) {
return dump(kv.Key) + "=>" + dump(kv.Value);
}
public static string dump<T>(IEnumerable<T> list) {
StringBuilder result = new StringBuilder("{");
foreach(T t in list) {
result.Append(dump(t));
result.Append(", ");
}
result.Append("}");
return result.ToString();
}
but the second overload never gets called. For example:
List<string> list = new List<string>();
list.Add("polo");
Dictionary<int, List<string>> dict;
dict.Add(1, list);
Console.WriteLine(dump(dict));
I'm expecting this output:
{1=>{"polo", }, }
What actually happens is this:
dict is correctly interpreted as an IEnumerable<KeyValuePair<int, List<string>>>, so the 3rd overload is called.
the 3rd overload calls dump on a KeyValuePair>. This should(?) invoke the second overload, but it doesn't -- it calls the first overload instead.
So we get this output:
{[1=>System.Collections.Generic.List`1[System.String]], }
which is built from KeyValuePair's .ToString() method.
Why isn't the second overload called? It seems to me that the runtime should have all the information it needs to identify a KeyValuePair with full generic arguments and call that one.
Generics is a compile time concept, not run time.
In other words the type parametes are resolved at compile time.
In your foreach you call dump(t) and t is of type T.
But there is nothing known about T at this point other than that it is an Object.
That's why the first overload is called.
(updated) As mentioned in other answers, the problem is that the compiler does not know that type V is actually a List<string>, so it just goes to dump(object).
A possible workaround might be to check types at run time. Type.IsGenericType will tell you if the type of a variable has generics or not, and Type.GetGenericArguments will give you the actual type of those generics.
So you can write a single dump method receiving an object and ignoring any generics info. Note that I use the System.Collections.IEnumerable interface rather than System.Collections.Generics.IEnumerable<T>.
public static string dump(Object o)
{
Type type = o.GetType();
// if it's a generic, check if it's a collection or keyvaluepair
if (type.IsGenericType) {
// a collection? iterate items
if (o is System.Collections.IEnumerable) {
StringBuilder result = new StringBuilder("{");
foreach (var i in (o as System.Collections.IEnumerable)) {
result.Append(dump(i));
result.Append(", ");
}
result.Append("}");
return result.ToString();
// a keyvaluepair? show key => value
} else if (type.GetGenericArguments().Length == 2 &&
type.FullName.StartsWith("System.Collections.Generic.KeyValuePair")) {
StringBuilder result = new StringBuilder();
result.Append(dump(type.GetProperty("Key").GetValue(o, null)));
result.Append(" => ");
result.Append(dump(type.GetProperty("Value").GetValue(o, null)));
return result.ToString();
}
}
// arbitrary generic or not generic
return o.ToString();
}
That is: a) a collection is iterated, b) a keyvaluepair shows key => value, c) any other object just calls ToString. With this code
List<string> list = new List<string>();
list.Add("polo");
Dictionary<int, List<string>> dict = new Dictionary<int, List<string>>() ;
dict.Add(1, list);
Console.WriteLine(dump(list));
Console.WriteLine(dump(dict.First()));
Console.WriteLine(dump(dict));
you get the expected output:
{marco, }
1 => {marco, }
{1 => {marco, }, }
To call the second version in your foreach, you need to specify the template parameters K and V, otherwise it will always call the first version:
dump(t); // always calls first version
dump<K,V>(t); // will call the second
How you get the parameter types K and V is another question....

Categories