Imagine in a class you got this Method:
float Do(int a_,string b_){}
I'm trying to do something like this:
float Do(int a_, string b_)
{
var params = GetParamsListOfCurrentMethod(); //params is an array that contains (a_ and b_)
}
Can someone help ?
Why should I want to do thet ?
Imagine you got an Interface:
public Interface ITrucMuch
{
float Do(int a_,string b_);
// And much more fct
}
And a lot of classes implementing that interface
And a special class that also implement interface:
public class MasterTrucMuch : ITrucMuch
{
public floatDo(int a_, string b_)
{
ITrucMuch tm = Factory.GetOptimizedTrucMuch(); // This'll return an optimized trucMuch based on some state
if(tm != null)
{
return tm.Do(a_,b_);
}
else
{
logSomeInfo(...);
}
//do the fallback method
}
As the interface constains a lot of method and as the first lien of all method are always the same (checking if there is a better interface that the current instance and if so call the same method on the instance) I try to make a method of it.
Thx
You could do something like this:
var parameters = MethodBase.GetCurrentMethod().GetParameters();
foreach (ParameterInfo parameter in parameters)
{
//..
}
Have a look at the ParameterInfo class.
var params = GetParamsListOfCurrentMethod();
params is a C# keyword so it can't be used as a variable name as above.
Here's a link on how to use the params keyword
http://msdn.microsoft.com/en-us/library/w5zay9db.aspx
And some example code pulled form the article.
public static void UseParams(params int[] list)
{
for (int i = 0; i < list.Length; i++)
{
Console.Write(list[i] + " ");
}
Console.WriteLine();
}
Use Reflection .NET to get the parameter names for the method.
Using reflection to get method name and parameters
or
http://msdn.microsoft.com/en-us/library/system.reflection.parameterinfo.aspx
you can write your function with dynamic parameter like this:
protected void Do(params object[] list)
{
if (list.Length < 2)
return;
int a_=(int)list[0];
string b_=list[1].ToString();
}
I don't get it. If you want the param values, and this is the method you need to work with, what about simple doing
protected void Do(int a_, string b_)
{
var paramValues = new object[]{a_, b_};
}
Do you want a more generic answer? Then you are duplicating questions Can I get parameter names/values procedurally from the currently executing function? and How to get parameter value from StackTrace
And you can't, basically.
Related
All methods in the "ProbabilitiesTheory" class accept dynamic count of parameters - it means that there can be put as many parameters as one wants. But .NET still says "System.Reflection.TargetParameterCountException" when invoking a method, that has "params" keyword in its parameters.
Here's the code:
internal static class ProbabilitiesTheory
{
static public double GetMediumValue(params double[] integers)
{ }
}
class Program
{
static void Main(string[] args)
{
MethodInfo[] methods = Type.GetType("ConsoleApplication1.ProbabilitiesTheory").GetMethods();
while (true)
{
Console.WriteLine("Write the name of the method\n");
string NameOfMethod = Console.ReadLine();
Console.WriteLine("Write the parameters of the method using the following format:
parameter1;parameter2;parameter3;parameterN\n");
string ParametersOfMethod = Console.ReadLine();
foreach (var i in methods)
{
if (i.Name == NameOfMethod)
{
object[] #parameters = (from t in ParametersOfMethod.Split(';') where t != "" select (object)Convert.ToDouble(t)).ToArray();
i.Invoke(null, #parameters); // Exception HERE
}
}
Console.WriteLine("______");
}
}
}
It is absolutely ok with LINQ expression there, i get what i need to get: object[] containing dynamic amount of double values.
How do i solve this problem?
As far as reflection is concerned, a params array is just an array with a fancy syntactical sugar. You could solve the immediate problem for most of your methods by adjusting your code like so:
double[] #parameters = (from t in ParametersOfMethod.Split(';') where t != "" select Convert.ToDouble(t)).ToArray();
i.Invoke(null, new[] { #parameters});
The gist of this is that a params array is just a single parameter at run-time, and the ability to add a variable amount of values to it is just a nicety done by the compiler.
You can confirm this with a snippet like this:
void Main()
{
var parameterCount = typeof(Test).GetMethod("Foo").GetParameters().Count();
Console.WriteLine(parameterCount); // Output: 2
}
// Define other methods and classes here
public static class Test
{
public static void Foo(double x, params double[] y)
{}
}
If you need to invoke a function that uses a params array with user provided values when the params array is not the only parameter, you're going to need to get the method parameter count and work out where the array actually starts, then wrap things accordingly.
I have a simple helper class that I use to build a simple comma separated string.
private string AddcsvString(string s)
{
if(string.IsNullOrWhiteSpace(this.Value))
{
return s;
}
else
{
return this.Value + "," + s;
}
}
I also have a generic method that calls this
public void Add<T>(T s) where T: struct
{
this.Value = AddcsvString(s.ToString());
}
I wanted to add an overload for a generic List
public void Add<T>(IEnumerable<T> values)where T:struct
{
foreach (T t in values)
{
Add(t.ToString());
}
}
But any attempt to call this called the first generic method. So I ended up renaming the second generic method to AddAll. In the end I think this was the right way to go for this case but would like to know if it is possible to have both for future reference.
--edit
Here is the case that doesn't work
CsvString test = new CsvString();
string result;
test.Add(1);
test.Add('2');
test.Add("3");
result = test.ToString(); // result = "1,2,3"
CsvString test2 = new CsvString();
List<long> aList = new List<long>();
string result2;
aList.Add(1);
aList.Add(2);
aList.Add(3);
test2.Add(aList); //line doesn't compile
--edit 2
I found a second solution (though JoshE below gets credit for answering this, thanks btw).
I changed the second method to this
public SWcsvString Add<T,K>(T values)where T: IEnumerable<K> where K: struct
{
foreach (K k in values)
{
Add(k.ToString());
}
return this;
}
and the call to this
test2.Add<IEnumerable<long>,long>(aList);
Try removing your constraints where T : struct, and I think you will get the proper behavior.
IEnumerable<char> <==> String, since a string is just a char[]. Since a string is not really a value-object, overload resolution will almost always favor the first method to avoid the boxing/unboxing operation of converting a string to IEnumerable<char>. (I'm guessing that you've tried calling it with both "foo" and IEnumerable<bar> where bar is a struct).
In C#,I have a public function that can pass a List parameter, with T is a custom class. The function can pass with different T class. The problem that how to verify the type of T in every case?
public static List<T> ConvertData(List<T> oldDatas)
{
//I will analyze the object T,
//but now i don't know how to verify the type of T,
//with T can change,
//example maybe T is T1 class,or T2 class..
}
Thanks for my stupid question.
this is for C#
Type gt = typeof(T);
check this for java : Get generic type of java.util.List
just do :
public static class Test<T>
where T : class, new()
{
public static List<T> ConvertData(List<T> oldDatas)
{
T instanceOfT = new T();
Type typeOfT = typeof(T); // or instanceOfT.GetType();
if(instanceOfT is string)
{
// T is a string
}
else if(instanceOfT is int)
{
// T is an int
}
// ...
}
}
But that isn't productive and break the generic concept... Explain what you're trying to do.
Do you need to make different converting depends on or just want to check for specific classes? In second case you can try to specify right types for T something like:
public static List<string> ConvertData(List<string> data)
{
return PrivateConvertData<string>(data);
}
public static List<int> ConvertData(List<int> data)
{
return PrivateConvertData<int>(data);
}
private static List<T> PrivateConvertData<T>(List<T> data)
{
// code here
}
This code will check type of T during compilation.
You can use the typeof(T) keyword or use some check (if you are expecting some types to be passed via parameters):
public static List<T> ConvertData(List<T> oldDatas)
{
foreach (var itemList in oldDatas)
{
if (itemList is LinqType)
{
var linqTypeItem = (LinqType) itemList;
Console.WriteLine(linqTypeItem.PROPERTY_YOU_NEED);
}
// or
var linqTypeItem = itemList as LinqType;
if (linqTypeItem != null)
{
Console.WriteLine(linqTypeItem.PROPERTY_YOU_NEED);
}
}
}
Also you can use the Cast() method. More information here
Hi
i have created a Generic Array that works fine for Int,String, Float or even my Own type named Customers.
Generic Array has functions Add(), Sort(), ShowAll() thats working fine for Int, String, and even Customer Type
except when i try to showAll() method for CustomerType that shows all the values that i have added through ADD() method.
output is something like
GenericArray.Customer
not the values where as i wanted to have the values .
i have solved it through
public class GArray<T> where T : Customer
but now i cant create Generic Array of type Int,Float .
here is the ADD and ShowAll method of Class
public void Add(T temp)
{
if (index >= values.Length)
{
T[] tempArray = new T[values.Length + 1];
Array.Copy(values, tempArray, values.Length);
values = tempArray;
}
values[index] = temp;
index++;
}
public void ShowAll()
{
for (int i = 0; i < values.Length; i++)
{
Console.WriteLine(values[i]);
}
}
the values m adding
static void Main(string[] args)
{
GArray<Customer> customers = new GArray<Customer>(3);
customers.Add(new Customer(101, "xyz"));
customers.Add(new Customer(59, "abc"));
customers.ShowAll();
}
i have talked with my frnd and he said that i have to create indexer my self . can some one help me how can i create indexer in this case that works fine for customerType or any Type.
I think,If I understand the question (output is something like GenericArray.Customer, not the values where as i wanted to have the values) you should add in Customer definition:
public override string ToString()
{
// return something you want to show to identify your customer
// e.g. return Name;
return ...
}
I explain: when you use Console.WriteLine(values[i]) you tell C# to write to console Customer object... and it writes out then name of the class, as it's the default behaviour.
Defining in Customer class the default string to be converted to makes what you please...
public T this[int index]
{
get {return values[index]; }
}
I think your problem is that you have not overridden ToString in your customer class. Do that -- it will define how the objects should be displayed in the console.
Your actual problem aside for a moment, I would like to mention that there is no place for a ShowAll method in an array implementation. Why should an array be tied to a console application? Wouldn't you want to reuse it for a Windows Forms application oneday without the need to rewrite it?
Next, .NET already has a List<T> which does dynamic allocation as necessary. If you do want to write it again yourself, at least allocate the array in bigger steps (n*2 each time).
To remove the ShowAll method from the array (where it doesn't belong), you should consider taking one of the following approaches:
a) Create an extension method which works for any IEnumerable<T> (a List, Array, Collection, whatever):
public static class EnumExt
{
public static void ShowAll<T>(this IEnumerable<T> list)
{
foreach (T item in list)
Console.WriteLine(item);
}
}
Usage:
int[] array = new int[] { 1,2,3};
array.ShowAll();
b) Or, be even more abstract and create a ForEach extension method where you will pass an arbitrary delegate to perform actual work:
public static class EnumExt
{
public static void ForEach<T>(this IEnumerable<T> list, Action<T> action)
{
foreach (T item in list)
action(item);
}
}
Usage:
int[] array = new int[] { 1,2,3};
// now you are reusing the iterator
// for any action you want to execute
array.ForEach(Console.WriteLine);
// or
array.ForEach(item => Console.WriteLine("My item is: " + item));
I am having trouble casting an object to a generic IList. I have a group of in statements to try to work around this, but there has to be a better way to do this.
This is my current method:
string values;
if (colFilter.Value is IList<int>)
{
values = BuildClause((IList<int>)colFilter.Value, prefix);
}
else if (colFilter.Value is IList<string>)
{
values = BuildClause((IList<string>)colFilter.Value, prefix);
}
else if (colFilter.Value is IList<DateTime>)
{
values = BuildClause((IList<DateTime>)colFilter.Value, prefix);
}
else if (...) //etc.
What I want to do is this:
values = BuildClause((IList<colFilter.ColumnType>)colFilter.Value, prefix);
or
values = BuildClause((IList<typeof(colFilter.ColumnType)>)colFilter.Value, prefix);
or
values = BuildClause((IList<colFilter.ColumnType.GetType()>)colFilter.Value, prefix);
Each of these produces this compiler error:
The type or namespace name 'colFilter' could not be found (are you missing a using directive or an assembly reference?)
In my example, colFilter.ColumnType is int, string, datetime, etc. I am not sure why this does not work.
Any ideas?
EDIT: This is C#2.0
EDIT #2
Here is the BuildClause method (I have overloads for each type):
private static string BuildClause(IList<int> inClause, string strPrefix)
{
return BuildClause(inClause, strPrefix, false);
}
private static string BuildClause(IList<String> inClause, string strPrefix)
{
return BuildClause(inClause, strPrefix, true);
}
private static string BuildClause(IList<DateTime> inClause, string strPrefix)
{
return BuildClause(inClause, strPrefix, true);
}
//.. etc for all types
private static string BuildClause<T>(IList<T> inClause, string strPrefix, bool addSingleQuotes)
{
StringBuilder sb = new StringBuilder();
//Check to make sure inclause has objects
if (inClause.Count > 0)
{
sb.Append(strPrefix);
sb.Append(" IN(");
for (int i = 0; i < inClause.Count; i++)
{
if (addSingleQuotes)
{
sb.AppendFormat("'{0}'", inClause[i].ToString().Replace("'", "''"));
}
else
{
sb.Append(inClause[i].ToString());
}
if (i != inClause.Count - 1)
{
sb.Append(",");
}
}
sb.Append(") ");
}
else
{
throw new Exception("Item count for In() Clause must be greater than 0.");
}
return sb.ToString();
}
There's no way to relate method overloading and generics: although they look similar, they are very different. Specifically, overloading lets you do different things based on the type of arguments used; while generics allows you to do the exact same thing regardless of the type used.
If your BuildClause method is overloaded and every overload is doing something different (not just different by the type used, but really different logic, in this case - choosing whether or not to add quotes) then somewhere, ultimately, you're gonna have to say something like "if type is this do this, if type is that do that" (I call that "switch-on-type").
Another approach is to avoid that "switch-on-type" logic and replace it with polymorphism. Suppose you had a StringColFilter : ColFilter<string> and a IntColFilter : ColFilter<int>, then each of them could override a virtual method from ColFilter<T> and provide its own BuildClause implementation (or just some piece of data that would help BuildClause process it). But then you'd need to explicitly create the correct subtype of ColFilter, which just moves the "switch-on-type" logic to another place in your application. If you're lucky, it'll move that logic to a place in your application where you have the knowledge of which type you're dealing with, and then you could explicitly create different ColFilters at different places in your application and process them generically later on.
Consider something like this:
abstract class ColFilter<T>
{
abstract bool AddSingleQuotes { get; }
List<T> Values { get; }
}
class IntColFilter<T>
{
override bool AddSingleQuotes { get { return false; } }
}
class StringColFilter<T>
{
override bool AddSingleQuotes { get { return true; } }
}
class SomeOtherClass
{
public static string BuildClause<T>(string prefix, ColFilter<T> filter)
{
return BuildClause(prefix, filter.Values, filter.AddSingleQuotes);
}
public static string BuildClause<T>(string prefix, IList<T> values, bool addSingleQuotes)
{
// use your existing implementation, since here we don't care about types anymore --
// all we do is call ToString() on them.
// in fact, we don't need this method to be generic at all!
}
}
Of course this also gets you to the problem of whether ColFilter should know about quotes or not, but that's a design issue and deserves another question :)
I also stand by the other posters in saying that if you're trying to build something that creates SQL statements by joining strings together, you should probably stop doing it and move over to parameterized queries which are easier and, more importantly, safer.
What does the function BuildClause() look like.
It seems to me that you can create BuildClause() as an extension method on IList, and you can append the values together. I assume that you just want to call .ToString() method on different types.
If you use generics properly in C# 3.0, you can achieve what you need through implicit typing (int C# 2.0 you might need to specify the type). If your BuildClause method is made generic, it should automatically take on whatever type is passed in to its generic parameter(s):
public IList<T> BuildClause<T>(IList<T> value, object prefix)
{
Type type = typeof(T);
if (type == typeof(string))
{
// handle string
}
else if (type == typeof(int))
{
// handle int
}
// ...
}
public class ColumnFilter<T>:
where T: struct
{
public IList<T> Value { get; set; }
}
var colFilter = new ColumnFilter<string>
{
Value = new { "string 1", "string 2", "string 3" }
}
IList<string> values = BuildClause(colFilter.Value, prefix);
With generics, you can drop the ColumnType property of your ColumnFilter. Since it is generic, along with your BuildClause method, you are easily able to determine the type by doing typeof(T).
I am having trouble casting an object to a generic
Casting is a run-time operation.
Generic is compile-time information.
Don't cross the streams.
Also - if you used a decent sql parameterization generator - it will add the single quotes for you.
I don't understand the question. It works for me. It could be as simple as droping the cast? What am I missing?
using System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApplication1 {
class Foo<T> : List<T> {
}
class Program {
static void Main(string[] args) {
var a = new Foo<int>();
a.Add(1);
var b = new Foo<string>();
b.Add("foo");
Console.WriteLine(BuildClause(a, "foo", true));
Console.WriteLine(BuildClause(b, "foo", true));
}
private static string BuildClause<T>(IList<T> inClause, string strPrefix, bool addSingleQuotes) {
StringBuilder sb = new StringBuilder();
//Check to make sure inclause has objects
if (inClause.Count == 0)
throw new Exception("Item count for In() Clause must be greater than 0.");
sb.Append(strPrefix).Append(" IN(");
foreach (var Clause in inClause) {
if (addSingleQuotes)
sb.AppendFormat("'{0}'", Clause.ToString().Replace("'", "''"));
else
sb.Append(Clause.ToString());
sb.Append(',');
}
sb.Length--;
sb.Append(") ");
return sb.ToString();
}
}
}
The type for the IList must be known at compile time. Depending on what you want to do, you might be able to cast the list to an IList or IEnumerable (without generics) and then iterate over the objects