Currently am doing a college project in C# which includes conversion of one form of code to another form of code, which involves choosing appropriate method/function from many methods available. The problem here is, to implement this using any pattern matching techniques rather then using many IF ELSE statements.
For now I have achieved this using nested IF ELSE statements which fills the whole program and looks like childish code on completion.
Current Implementation :--
Input:
//stored in list<string>
get(3 int) //type1
get(int:a,b,c) //type2
get(name) //type3
//list passed to ProcessGET method
Using if else :
public string ProcessGET(List<string> inputData)
{
foreach(var item in inputData)
{
if (inputData.item.Split('(')[1].Split(')')[0].Contains(':'))
{
return Type2 result;
}
else if (!inputData.item.Split('(')[1].Split(')')[0].Contains(':') && Convert.ToInt32(inputData.item.Split('(')[1].Split(')')[0].Split(' ')[0])>0)
{
return Type1 result;
}
else
{
return Type3 result;
}
}
}
How I wanted this to be is something like this,
/stored in list<string>
get(3 int) //type1
get(int:a,b,c) //type2
get(name) //type3
//list passed to ProcessGET method
public string ProcessGET(List<string> inputData)
{
foreach(var itm in inputData)
{
// call appropriate method(itm) based on type using some pattern matching techniques
}
}
string Method1(var data)
{
return result for type1;
}
string Method2(var data)
{
return result for type2;
}
string Method3(var data)
{
return result for type3;
}
Normally my program does mostly this kind of work for various types of input keywords like 'get','output','declare' etc etc etc... where Get is transformed to Scanf statements,output to printf statements and so on.
In such case if i use the IF ELSE, my project is full of If else statements.
As i just started to learn C#, I don't know if such thing exists(googled but didn't found what i was looking for), so any help regarding this problem will be very help(use)ful in further development.
Many Thanks in Advance.
Another general approach to this problem is to introduce an interface, say IMatcher. The interface has one method Match that returns either your type or maybe the fully transformed line.
You create multiple classes that implement IMatcher.
Your main loop then becomes:
var matchers = new [] { new MatcherA(), new MatcherB(), ... };
foreach (string line in input)
foreach (matcher in matchers)
{
var match = matcher.Match(line);
if (match != null) return match;
}
No more big if statement. Each matcher has its own small class and you can write unit tests for each. Also, use RegEx to make your matchers simpler.
I'll leave some suggestions here over which you can have a look at. Here's some basic code.
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
namespace TestStuff
{
class Program
{
//Input string should be of the form "<type>:<index>"
static dynamic GiveMeSomethingDynamic(string someInput)
{
/* predefined arrays sothat we can return something */
string[] _storedStrings = { "Word 1", "word 2", "word 3" };
int[] _storedInts = { 1, 2, 3 };
float[] _storedFloats = { 3.14f, 2.71f, 42.123f };
/* Parse the input command (stringly typed functions are bad, I know.) */
string[] splitted = someInput.Split(':');
string wantedType = splitted[0];
int index = int.Parse(splitted[1]);
/* Decide what to return base on that argument */
switch (wantedType)
{
case "int":
return _storedInts[index];
case "string":
return _storedStrings[index];
case "float":
return _storedFloats[index];
//Nothing matched? return null
default:
return null;
}
}
static void Main(string[] args)
{
/* get some return values */
dynamic firstOutput = GiveMeSomethingDynamic("string:0");
dynamic secondOutput = GiveMeSomethingDynamic("int:1");
dynamic thirdOutput = GiveMeSomethingDynamic("float:2");
/* Display the returned objects and their type using reflection */
Console.WriteLine("Displaying returned objects.\n" +
"Object 1: {0}\t(Type: {1})\n" +
"Object 2: {2}\t\t(Type: {3})\n" +
"Object 3: {4}\t\t(Type: {5})\n",
firstOutput, firstOutput.GetType(),
secondOutput, secondOutput.GetType(),
thirdOutput, thirdOutput.GetType());
/* Act on the type of a object. This works for *all* C# objects, not just dynamic ones. */
if (firstOutput is string)
{
//This was a string! Give it to a method which needs a string
var firstOutputString = firstOutput as string; //Cast it. the "as" casting returns null if it couldn't be casted.
Console.WriteLine("Detected string output.");
Console.WriteLine(firstOutputString.Substring(0, 4));
}
//Another test with reflection.
Console.WriteLine();
//The list of objects we want to do something with
string[] values = { "string:abcdef", "int:12", "float:3.14" };
foreach(var value in values)
{
/* Parse the type */
string[] parsed = value.Split(':');
string _type = parsed[0];
string _argument = parsed[1];
switch (_type)
{
case "string":
//This is a string.
string _stringArgument = _argument as string;
Method1(_stringArgument);
break;
case "int":
//Do something with this int
int _intArgument = int.Parse(_argument);
Method2(_intArgument);
break;
case "float":
float _floatArgument = float.Parse(_argument);
Method3(_floatArgument);
break;
default:
Console.WriteLine("Unrecognized value type \"{0}\"!", _type);
break;
}
}
Console.ReadLine();
}
public static void Method1(string s) => Console.WriteLine("String Function called with argument \"{0}\"", s);
public static void Method2(int i) => Console.WriteLine("int Function called with argument {0}", i);
public static void Method3(float f) => Console.WriteLine("float Function called with argument {0}", f);
}
}
The first approach, given by the function GiveMeSomethingDynamic() relies on the dynamic keyword, which can return arbitrary types. Depending on the input string, it can return a string, an int or a float. The method is called in the Main() function and the type of the returned objects is checked with e.g. firstOutput is string (the is operator). It could have also been done withif( firstOutput.GetType() == typeof(string))`.
The second approach would be a classical "parse and cast" technique. We parse an input string of the format <type>:<value>, then call different functions with the converted or parsed arguments. This is maybe what you want.
There's also a "hacky" way giving a function arbitrary types. There, you can just the dynamic keyword on an input argument, as in
public dynamic superDynamic(dynamic inputVar)
{
//Figure out the type of that object
//return something dynamic
}
The "oldschool" approach (not using dynamic) would be to only pass object types into each function, but the parsing is equivalent (if(someArgument.GetType() == typeof(string))...).
Hope this gives you some ideas on how to parse these strings, cast them to different types and call different functions with it.
So the types are stored as strings in a list, right? And you want to call a different function based on the value of the string?
Here's how I would finish your code:
Create an interface:
public interface IMyType
{
string Result();
string Input {get; set;}
}
and three classes which implement it:
public class Type1 : IMyType
{
public string Result()
{
// do something
}
public string Input {get; set;}
}
(repeat for Type2 and Type3)
3.then create a method which returns one of these three types
based on pattern matching your string input
public IMyType GetAppropriateType(string input)
{
if (inputData.item.Split('(')[1].Split(')')[0].Contains(':'))
{
return new Type2 {Input = input};
}
//etc
}
public string ProcessGET(List<string> inputData)
{
foreach(var itm in inputData)
{
IMyType type = GetAppropriateType(itm);
type.Result();
}
}
Probably worth looking at regex for your string matching too
Related
I've looked through many questions that are similar to this, but none of them really touched on what I precisely want to do. What I am trying to do is read from an external source a list of variables that also include their data type into a string array:
Example:
ID/Key Type Value/Data;
varName1 bool true;
varName2 string str;
varName3 int 5;
I then store these are objects into a dictionary as objects containing several strings, with the ID also serving as the key.
What I want to do is now create a method that uses a switch statement that casts the string into the correct datatype, and returns it without having to specify anything in the method call. The function should look something like this:
public ??? Method(string key)
{
if(dictionary.ContainsKey(ID))
{
Var temp = dictionary[ID];
switch (temp.Type)
{
case "bool":
return Convert.ToBoolean(temp.Value);
case "int"
return Convert.ToInt(temp.Value);
case "string"
return temp.Value;
}
}
return "NULL";
}
The method call should look something like this:
int x = Method(string key);
string word = Method(string key);
bool isTrue = Method(string key);
Maybe I've missed something, but I have yet to find something that really does something quite like this. Any and all thoughts about this are welcome as well.
In C# 7 you have the option to return multiple values from a method like this:
public (string SomeString, int SomeInt) DoSomething() { ... }
You can get the values like this:
var result = DoSomething();
Console.WriteLine(result.SomeString);
Console.WriteLine(result.SomeInt.ToString());
Or
(var someString, var someInt) = DoSomething();
Console.WriteLine(someString);
Console.WriteLine(someInt.ToString());
This works below the surface with a Tuple and you are not restricted to only 2 values. I don't know how many you can return but I suggest when you need to return that many values, create a class.
More info: https://blogs.msdn.microsoft.com/dotnet/2016/08/24/whats-new-in-csharp-7-0/
Update
I believe a lot of people are arriving at this question because they're looking for ways to return multiple values generally, not necessarily for the purposes given in the original question. If this is what you want, there are a few options to choose from.
If the combination of your returned types represents a concept that may be useful outside of your method call, consider creating a type to represent that concept. C#'s records provide a nice, concise way to do that:
public record ExtractedValue(bool? BooleanValue, string? StringValue, int? IntValue);
public ExtractedValue Method(string key)
{
...
}
If this is the only place these values will appear together, and it's not really worth coming up with a named type to represent the values, you can also use a Value Tuple. Just be aware that there are some behavioral implications that might bite you if you plan to use the type for things like serialization.
public (bool? BooleanValue, string? StringValue, int? IntValue) Method(string key)
{
...
}
Original Answer
The compiler has no way to distinguish between the three method calls you've provided, because they all look like Method(key);
One option is to return an object and then expect the consuming code to cast it to what they want:
public object Method(string key)
{
if(dictionary.ContainsKey(key))
{
var temp = dictionary[key];
switch (temp.Type)
{
case "bool":
return Convert.ToBoolean(temp.Value);
case "int"
return Convert.ToInt(temp.Value);
case "string"
return temp.Value;
}
}
return "NULL";
}
...
int x = (int) Method(key);
string word = (string) Method(key);
bool isTrue = (bool) Method(key);
You could also use the dynamic keyword to make the cast implicit:
public dynamic Method(string key)
{
if(dictionary.ContainsKey(key))
{
var temp = dictionary[key];
switch (temp.Type)
{
case "bool":
return Convert.ToBoolean(temp.Value);
case "int"
return Convert.ToInt(temp.Value);
case "string"
return temp.Value;
}
}
return "NULL";
}
...
int x = Method(key);
string word = Method(key);
bool isTrue = Method(key);
However, dynamic is a very powerful concept, and it's easy for it to get out of hand, so you have to be really careful with that.
It seems to me that you're expecting your calling code to know which type of object it's expecting to get for each key. It seems like maybe the best approach is to just let the user supply that information:
public T Method<T>(string key)
{
if(dictionary.ContainsKey(key))
return (T) Convert.ChangeType(dictionary[key].Value, typeof(T));
return default(T);
}
...
int x = Method<int>(key);
string word = Method<string>(key);
bool isTrue = Method<bool>(key);
That way, there's no need to track the Type value in your dictionary objects in the first place.
The return type of a function must be typed. As with any other variable or operation, any type that inherits from the specified type is a valid return value (which is why object allows anything as a value).
Personally i dont think it is useful to make one method with multiple return types but if you really want to have one method with multiple return types, you could use the dynamic type in .NET 4.0:
private static void Main(string[] args)
{
int x = Method("varName3");
string word = Method("varName2");
bool isTrue = Method("varName1");
}
private static dynamic Method(string key)
{
var dictionary = new Dictionary<string, KeyValuePair<Type, object>>()
{
{ "varName1", new KeyValuePair<Type, object>(typeof(bool), false) },
{ "varName2", new KeyValuePair<Type, object>(typeof(string), "str") },
{ "varName3", new KeyValuePair<Type, object>(typeof(int), 5) },
};
if (dictionary.ContainsKey(key))
{
return dictionary[key].Value;
}
return null;
}
Hope it helps
I have enum:
enum MyEnum{
aaaVal1,
aaaVal2,
aaaVal3,
}
I need to have abbreviated version of 'MyEnum' which maps every item from 'MyEnum' to different values. My current approach is method which simply translates every item:
string translate(MyEnum myEnum)
{
string result = "";
switch ((int)myEnum)
{
0: result = "abc";
1: result = "dft";
default: result = "fsdfds"
}
return result;
}
the problem with this approach is that every time programmer changes MyEnum he should also change translate method.
This is not a good way of programming.
So..
Is there any more elegant solution for this problem?
Thank you :-)
Four options:
Decorate your enum values with attributes, e.g.
enum MyEnum
{
[Description("abc")]
AaaVal1,
[Description("dft")]
AaaVal2,
AaaVal3,
}
Then you can create a mapping (like the dictionary solution below) via reflection.
Keep the switch statement but switch on the enum value instead of a number for better readability:
switch (myEnum)
{
case MyEnum.AaaVal1: return "abc";
case MyEnum.AaaVal2: return "dft";
default: return "fsdfds";
}
Create a Dictionary<MyEnum, string>:
private static Dictionary<MyEnum, string> EnumDescriptions =
new Dictionary<MyEnum, string>
{
{ MyEnum.AaaVal1, "abc" },
{ MyEnum.AaaVal2, "dft" },
};
You'd need to handle the defaulting in the method, of course.
Use a resource file, with an entry for each string representation. This would be better if you're really trying to translate in a way that might need different translations for different cultures.
Considering that the use of descriptors on enums is quite common, here it's a good-enough class to do it:
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
class EnumDescriptor : Attribute
{
public readonly string Description;
public EnumDescriptor(string description)
{
this.Description = description;
}
public static string GetFromValue<T>(T value) where T : struct
{
var type = typeof(T);
var memInfo = type.GetField(value.ToString());
var attributes = memInfo.GetCustomAttributes(typeof(EnumDescriptor), false);
if (attributes.Length == 0)
{
return null;
}
return ((EnumDescriptor)attributes[0]).Description;
}
}
enum MyEnum
{
[EnumDescriptor("Hello")]
aaaVal1,
aaaVal2,
aaaVal3,
}
string translate(MyEnum myEnum)
{
// The ?? operator returns the left value unless the lv is null,
// if it's null it returns the right value.
string result = EnumDescriptor.GetFromValue(myEnum) ?? "fsdfds";
return result;
}
I'm finding what you're trying to do a bit weird.
If you're making translations, then you should create a RESX file and create ACTUAL translations.
But to answer your question, I guess you could create another enum with the same amount of fields and same numbering (if you're using anything other than the default) and have that act as the abbreviated names. Connecting one to the other should be straightforward:
string GetAbbreviation(Enum1 enum1)
{
return ((Enum2)((int)enum1)).ToString();
}
Attributes will be nice solution for this case. You can specify translations for enumeration members via declarative way:
public class TranslateAttribute
{
public string Translation { get; private set; }
public TranslateAttribute(string translation)
{
Translation = translation;
}
}
enum MyEnum
{
[Translate("abc")]
aaaVal1,
[Translate("dft")]
aaaVal2,
[Translate("fsdfds")]
aaaVal3
}
After this you should write common method for obtaining translations. It should check attribute with translation (via reflection) and return translation if it was specified and default value in other cases.
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).
I read that the 'if' keyword is evil, and better to use predicate to replace if. Then I googled, but still dont get it.
Can anyone be kind to provide an example?
No matter what they say, if is not evil. There may be specific cases for which a Predicate is a better choice than an if (or a set of ifs).
For example,
foreach (Foo f in fooList) {
if (f.Equals(fooTarget)) {
return f;
}
}
versus (.NET 2.0)
fooList.Find(delegate (Foo f) { return f.Equals(fooTarget); });
or (later)
fooList.Find(f => f.Equals(fooTarget));
They are just different. A predicate is more complex than a simple if statement. A predicate is basically a pointer to a method (delegate) which is tied to a type that it takes as a param and returns true/false.
Imagine you are using generics, and like the find method on generic lists, how can it know what types are in the list prior to your initialization of it. So the find method just uses the predicate and does not know how the predicate will be implemented.
public T Find(Predicate<T> p)
{
//iterate through the collection and return the first match
IEnumerator<T> enumerator = this.GetEnumerator();
while (enumerator.MoveNext())
{
if (p(enumerator.Current))
{
return enumerator.Current;
}
}
return default(T);
}
In this case, a predicate is used but what (p(enumerator.Current)) actually evaluates about enumerator.Current is determined during implementation of the predicate. The code is not aware of what type T wil end up being here.
Here are some ways to assign the predicate to a method
Predicate<string> findShortNames1 = x => x.Length == 3; // lambda expression
Predicate<string> findShortNames2 = delegate(string x) { return x.Length == 3; }; // anonymous method
Predicate<string> findShortNames3 = MatchOnShortNames; //existing method
// ...
private bool MatchOnShortNames(string s)
{
return s.Length == 3;
}
Then the usage is like
someList.FindAll(findShortNames1);
For example, whenever you have a loop like this:
List<Employee> retiredEmployees = new List<Employee>();
foreach (Employee employee in EmployeeList)
{
if (employee.IsRetired)
retiredEmployees.Add(employee);
}
Using a predicate, you would have to change it to:
retiredEmployees = EmployeeList.FindAll(e => e.IsRetired);
But I believe, in the whole "if statement considered evil" debate, predicate vs if is just mentioned as a special case of using OOP and functional programming vs procedural programming. This paradigm can be easily generalized to any delegate type (not just predicate), or any use of OOP to replace a conditional:
For example, if you go through your code, you may easily find code such as this:
public class Employee
{
private bool _isRetired;
private double _amount;
public double GetPayAmount()
{
if (_isRetired)
return _amount * 0.9;
else
return _amount;
}
}
Pure OOP supporters will tell you that you immediately need to extract a different type of employee and handle each branch as a different subtype, which will remove the "evil if statement":
public interface IEmployee
{
double GetPayAmount();
}
public class Employee : IEmployee
{
private double _amount;
public double GetPayAmount()
{
return _amount;
}
}
public class RetiredEmployee : IEmployee
{
private double _amount;
public double GetPayAmount()
{
return _amount * 0.9;
}
}
Although the code is easier to maintain this way, the amount of code in the second case has clearly doubled. For a simple hierarchy as this, there is little need to do the refactoring at this phase. If you decide that you need many more special cases, then your conditional might become too complex, and you can easily refactor it later.
I don't use them for straight "if ... else" constructs myself, other than withinn searches, as it also removes the need for loop constructs. For example
int index = this.listObjects.FindIndex(x => x.PropertyA == objectItem.PropertyA);
or
List<ClassA> listClass = new List<ClassA>();
//... some more code filling listClass with ClassA types ...
ClassA tempClassA = listClass.FirstOrDefault().Where(x=> x.PropertyA == someValue);
I must admit though that if there's just a straight comparison to perform on one item then I use and "if ... else" construct.
static void Main()
{
string[] names = { "Lukasz", "Darek", "Milosz" };
foreach (var item in names)
{
if (ContainsL(item))
Console.WriteLine(item);
}
string match1 = Array.Find(names, delegate(string name) { return name.Contains("L"); });
//or
string match2 = Array.Find(names, delegate(string name) { return name.Contains("L"); });
//or
string match3 = Array.Find(names, x => x.Contains("L"));
Console.WriteLine(match1 + " " + match2 + " " + match3); // Lukasz Lukasz Lukasz
}
static bool ContainsL(string name) { return name.Contains("L"); }
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