I'm trying to convert a HttpRequest.QueryString to object[] with this extension method:
public static object[] ToObjectArray(this NameValueCollection nvc)
{
var ret = new object[nvc.Count];
var count = 0;
foreach (string s in nvc)
{
var strings = nvc.GetValues(s);
if (strings != null)
{
foreach (string v in strings)
{
ret[count] = new { s = v };
}
}
count++;
}
return ret;
}
var args = request.QueryString.ToObjectArray();
I think that I'm pretty close, but I'm getting the following exception:
Object of type '<>f__AnonymousType0`1[System.String]'
cannot be converted to type 'System.Object[]'.
What did I miss?
You don't need to convert v to a new object, a string is already an object, so you can just do:
ret[count] = v;
Here's a slightly shorter way, using a list to avoid having to keep up with the array index.
public static object[] ToObjectArray(this NameValueCollection nvc) {
List<object> results = new List<object>();
foreach (string key in nvc.Keys) {
results.Add(nvc.GetValues(key));
}
return results.ToArray();
}
Related
I want to get a list of each object from my List<T> (except strings, ints etc). And then Invoke (generic, recursive method with reflection). The problem is I am iterating on the property names, and have no idea how to select.
Error CS0021 Cannot apply indexing with [] to an expression of type 'T'
Code:
public static void My method<T>(IEnumerable<T> query)
{
var t = typeof(T);
var Headings = t.GetProperties();
for (int i = iteratorStart; i < Headings.Count(); i++)
{
if (IsValue(Headings[i].PropertyType.FullName))
{
}
else
{
Type type = Type.GetType(Headings[i].PropertyType.FullName);
var mi = typeof(ExcelExtension);
var met = mi.GetMethod("ListToExcel");
var genMet = met.MakeGenericMethod(type);
var nested = query.Select(p => p[Headings[i].Name]);
object[] parametersArray = new object[] { pck, nested, i };
genMet.Invoke(null, parametersArray);
}
}
}
As far as I can see, this is what you want:
public static void Mymethod<T>(IEnumerable<T> query)
{
var t = typeof(T);
int pck = 1234;
var mi = typeof(ExcelExtension);
var met = mi.GetMethod("ListToExcel");
var Headings = t.GetProperties();
for(int i=0; i < Headings.Length; ++i)
{
var prop = Headings[i];
if (prop.PropertyType.IsClass)
{
var genMet = met.MakeGenericMethod(prop.PropertyType);
var nested = query.Select(p => prop.GetValue(p));
object[] parametersArray = new object[] { pck, nested, i };
genMet.Invoke(null, parametersArray);
}
}
}
class ExcelExtension
{
public void ListToExcel<T>(int pck, IEnumerable<object> nested, int i)
{
}
}
Assuming you are using c# 6.0 or higher. You can use generic type parameters like;
public static void MyMethod<T>(IEnumerable<T> query) where T : IList
{
//Your code here
}
This way, you ensure that T is List of something and reaching indexing won't be a problem.
UPDATE
I misunderstood the question earlier. Here is the updated solution.
public static void MyMethod<T>(IEnumerable<T> query)
{
var t = typeof(T);
var Headings = t.GetProperties();
for (int i = iteratorStart; i < Headings.Count(); i++)
{
if (false == IsValue(Headings[i].PropertyType.FullName))
{
Type type = Type.GetType(Headings[i].PropertyType.FullName);
var mi = typeof(ExcelExtension);
var met = mi.GetMethod("ListToExcel");
var genMet = met.MakeGenericMethod(type);
//Assuming you want to get property value here. IF not You can use like Headings[i].GetName
var nested = query.Select(p =>Convert.ChangeType( Headings[i].GetValue(p),Headings[i].GetType()));
object[] parametersArray = new object[] { pck, nested, i };
genMet.Invoke(null, parametersArray);
}
}
}
Error Explanation:
The problem is in the Select(p => p[something here]) part. Since p is not the property list or array but a type of object, it doesn't contain any indexer. You should use reflection like above example.
This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 5 years ago.
I have a string which holds some words that i will be changing later by my methods :
example :
Hello $name How are you doing ?
i'm $ask
i will be changing $name and $ask using a method :
public static string ReturnLetter<T>(Dictionary<string, T> value)
{
var letter = File.ReadAllText("LETTER.html");
var newletter = "";
foreach (var type in value)
{
var item = type.Value;
var newstring = item.GetType().GetMethod("ReturnValue").Invoke(null, new object[] { }).ToString();
newletter = letter.Replace(type.Key, newstring);
}
return newletter;
}
i'm returning the Dictionary values with :
public static Dictionary<string, Type> returnDic()
{
var types = GetTypesInNamespace(Assembly.GetExecutingAssembly(), "ConsoleApplication11.Packets");
var Dic = new Dictionary<string, Type>();
foreach (var t in types)
{
Dic.Add(t.Name, t);
}
return Dic;
}
Types i holds is :
class name
{
private static string[] names =
{
"miri",
"sara",
};
public static string ReturnValue()
{
var random = new Random();
return names[random.Next(0, 1)];
}
}
I'm getting exception (null references) at
var newstring = item.GetType().GetMethod("ReturnValue").Invoke(null, new object[] { }).ToString();
i couldn't really track where the error is coming from !
i'm stuck at this for like an hour now
any help is appreciated
EDIT :
in the method which works :
public static string ReturnValue<T>()
{
return typeof(T).GetMethod("ReturnValue").Invoke(null,new object[] { }).ToString();
}
and then i realized that item.GetType() return RunTimeTime Instead of which typeof(T) returns .
As item seems to be a Type, try replacing
item.GetType().GetMethod("ReturnValue")...
with
item.GetMethod("ReturnValue")...
You were trying to find that method on class Type instead of class name. As it doesn't exist there, you get a null.
But a better architecture would use instance methods and interfaces. No reflection needed to invoke methods then.
I finally got to notice the issue !
in the method :
public static Dictionary<string, Type> returnDic()
{
var types = GetTypesInNamespace(Assembly.GetExecutingAssembly(), "ConsoleApplication11.Packets");
var Dic = new Dictionary<string, Type>();
foreach (var t in types)
{
Dic.Add(t.Name, t);
}
return Dic;
}
I'm returning a Type and not a T type and in the Replace Method i'm getting the Type of Type
foreach (var type in value)
{
var item = type.Value;
var newstring = item.GetType().GetMethod("ReturnValue").Invoke(null, new object[] { }).ToString(); ////// GetType() of Type
newletter = letter.Replace(type.Key, newstring);
}
i solved it by simple Converting type.Value to Type
var item = type.Value as Type;
I am trying to pass string array and other parameters in an object array,and on other side I want to retrieve this parameter values and display them, but I am not able to retrieve the string array values,rather it displays the type of the string array.
static void Main(string[] args)
{
string[] test = {"t1","t2","t3"};
TestArray(1,test,"Hello");
}
static void TestArray(params object[] array)
{
foreach(var value in array)
{
Console.WriteLine(value);
}
Console.ReadLine();
}
You're printing all values as string. Array.ToString() will return $elementType[], so System.String[] in your case.
You'll need to test if value is an IEnumerable, and if so, iterate over it and print its members' values, recursively.
static void TestArray(params object[] array)
{
PrintValue(value);
}
public void PrintValue(object value)
{
var enumerable = value as IEnumerable;
if (enumerable != null)
{
foreach (var subvalue in enumerable)
{
PrintValue(subvalue);
}
}
else
{
Console.WriteLine(value.ToString());
}
}
Do note that this still can't print complex types, and in that case, will just output its type name again.
Try this:
static void Main(string[] args)
{
string[] test = { "t1", "t2", "t3" };
TestArray(1, test, "Hello");
}
static void TestArray(params object[] array)
{
foreach (var value in array)
{
if (value is IEnumerable<object>)
foreach (var element in value as IEnumerable<object>)
Console.WriteLine(element);
else
Console.WriteLine(value);
}
Console.ReadLine();
}
You have to check if the value is an array and loop over it:
public static void DisplayParams(params object[] parameters)
{
foreach(var param in parameters)
{
var arr = param as string[];
if( arr != null)
{
foreach(var value in arr)
{
Console.WriteLine( value );
}
}
else
{
Console.WriteLine( param );
}
}
}
This part:
var arr = p as string[];
if( arr != null)
will check if its an array and will loop over it when it is.
Of course when you insert other types this won't work, so some validation would be wise
One option to consider:
static void Main(string[] args)
{
string[] test = { "t1", "t2", "t3" };
List<object> combined = new List<object> {1};
combined.AddRange(test);
combined.Add("Hello");
TestArray(combined.ToArray());
}
static void TestArray(params object[] array)
{
foreach (var value in array)
{
Console.WriteLine(value);
}
Console.ReadLine();
}
In short, you merge all the values into a single array before passing that array into the method.
If you went this route, consider removing the params keyword - so it makes it literally impossible for someone to call it the original way you had it. It forces them to think about how they want IEnumerables to be handled.
I have a collection of type List that I want to convert to SomeType[]. SomeType is not known before runtime.
This must be done with the signature of the following procedure.
private object ConvertListToArray(IList collection)
{
// This does not work since SomeType is not known before runtime.
var convertedList = collection.Cast<SomeType>().ToArray();
return convertedList;
}
Notice that collection is IList, but it is known that the concrete type is
List<SomeType>
The return collection must be an object of type SomeType[].
How can this be done?
public static class ListExtensions
{
public static T[] ConvertToArray<T>(IList list)
{
return list.Cast<T>().ToArray();
}
public static object[] ConvertToArrayRuntime(IList list, Type elementType)
{
var convertMethod = typeof(ListExtensions).GetMethod("ConvertToArray", BindingFlags.Static | BindingFlags.Public, null, new [] { typeof(IList)}, null);
var genericMethod = convertMethod.MakeGenericMethod(elementType);
return (object[])genericMethod.Invoke(null, new object[] {list});
}
}
[TestFixture]
public class ExtensionTest
{
[Test]
public void TestThing()
{
IList list = new List<string>();
list.Add("hello");
list.Add("world");
var myArray = ListExtensions.ConvertToArrayRuntime(list, typeof (string));
Assert.IsTrue(myArray is string[]);
}
}
You can do this with the implementation below:
class Program
{
static void Main(string[] args)
{
// same type
var myCollection = new List<string> {"Hello", "World"};
var array = (string[])myCollection.ConvertToArray();
Console.WriteLine(array[0]);
// new type
var intList = new List<int> {1, 2, 3};
var stringArray = (string[])intList.ConvertToArray(typeof(string));
Console.WriteLine(stringArray[0]);
// mixed types
var ouch = new List<object> {1, "Mamma", 3.0};
var result= (string[])ouch.ConvertToArray(typeof(string));
Console.WriteLine(result[0]);
}
}
The implementation:
public static class ListExtensions
{
public static object ConvertToArray(this IList collection)
{
// guess type
Type type;
if (collection.GetType().IsGenericType && collection.GetType().GetGenericArguments().Length == 0)
type = collection.GetType().GetGenericArguments()[0];
else if (collection.Count > 0)
type = collection[0].GetType();
else
throw new NotSupportedException("Failed to identify collection type for: " + collection.GetType());
var array = (object[])Array.CreateInstance(type, collection.Count);
for (int i = 0; i < array.Length; ++i)
array[i] = collection[i];
return array;
}
public static object ConvertToArray(this IList collection, Type arrayType)
{
var array = (object[])Array.CreateInstance(arrayType, collection.Count);
for (int i = 0; i < array.Length; ++i)
{
var obj = collection[i];
// if it's not castable, try to convert it
if (!arrayType.IsInstanceOfType(obj))
obj = Convert.ChangeType(obj, arrayType);
array[i] = obj;
}
return array;
}
}
You could try:
private T[] ConvertListToArray<T>(IList collection)
{
// This does not work since SomeType is not known before runtime.
var convertedList = collection.Cast<T>().ToArray();
return convertedList;
}
I'm posting this as the other answers seem a bit verbose. I'm pretty sure this does what the OP is looking for. It worked for me.
public static Array ConvertToArray(ICollection collection, Type type)
{
var array = Array.CreateInstance(type, collection.Count);
collection.CopyTo(array, 0);
return array;
}
This (shortened) code..
for (int i = 0; i < count; i++)
{
object obj = propertyInfo.GetValue(Tcurrent, new object[] { i });
}
.. is throwing a 'TargetParameterCountException : Parameter count mismatch' exception.
The underlying type of 'propertyInfo' is a Collection of some T. 'count' is the number of items in the collection. I need to iterate through the collection and perform an operation on obj.
Advice appreciated.
Reflection only works on one level at a time.
You're trying to index into the property, that's wrong.
Instead, read the value of the property, and the object you get back, that's the object you need to index into.
Here's an example:
using System;
using System.Collections.Generic;
using System.Reflection;
namespace DemoApp
{
public class TestClass
{
public List<Int32> Values { get; private set; }
public TestClass()
{
Values = new List<Int32>();
Values.Add(10);
}
}
class Program
{
static void Main()
{
TestClass tc = new TestClass();
PropertyInfo pi1 = tc.GetType().GetProperty("Values");
Object collection = pi1.GetValue(tc, null);
// note that there's no checking here that the object really
// is a collection and thus really has the attribute
String indexerName = ((DefaultMemberAttribute)collection.GetType()
.GetCustomAttributes(typeof(DefaultMemberAttribute),
true)[0]).MemberName;
PropertyInfo pi2 = collection.GetType().GetProperty(indexerName);
Object value = pi2.GetValue(collection, new Object[] { 0 });
Console.Out.WriteLine("tc.Values[0]: " + value);
Console.In.ReadLine();
}
}
}
I was most of the way there until I saw this, and I am posting this because I didn't see it anywhere else; the key was using GetValue(collection, new Object[] { i }); in the loop rather than trying to use GetValue(collection, new Object[i]); outside the loop.
(You can probably ignore the "output" in my example);
private static string Recursive(object o)
{
string output="";
Type t = o.GetType();
if (t.GetProperty("Item") != null)
{
System.Reflection.PropertyInfo p = t.GetProperty("Item");
int count = -1;
if (t.GetProperty("Count") != null &&
t.GetProperty("Count").PropertyType == typeof(System.Int32))
{
count = (int)t.GetProperty("Count").GetValue(o, null);
}
if (count > 0)
{
object[] index = new object[count];
for (int i = 0; i < count; i++)
{
object val = p.GetValue(o, new object[] { i });
output += RecursiveWorker(val, p, t);
}
}
}
return output;
}
Assembly zip_assembly = Assembly.LoadFrom(#"C:\Ionic.Zip.Reduced.dll");
Type ZipFileType = zip_assembly.GetType("Ionic.Zip.ZipFile");
Type ZipEntryType = zip_assembly.GetType("Ionic.Zip.ZipEntry");
string local_zip_file = #"C:\zipfile.zip";
object zip_file = ZipFileType.GetMethod("Read", new Type[] { typeof(string) }).Invoke(null, new object[] { local_zip_file });
// Entries is ICollection<ZipEntry>
IEnumerable entries = (IEnumerable)ZipFileType.GetProperty("Entries").GetValue(zip_file, null);
foreach (object entry in entries)
{
string file_name = (string)ZipEntryType.GetProperty("FileName").GetValue(entry, null);
Console.WriteLine(file_name);
}