I have code similar to the following in many places:
var dbParams = db.ReadParams(memberID, product, GetSubscriptionFields());
Debug.Assert(dbParams.Count == 4);
_memberCode = dbParams[0];
_password = dbParams[1];
_userName = dbParams[2];
_reasonCode = dbParams[3];
ReadParams() returns an array of strings, the number of strings depending on the GetSubscriptionFields() function. I could use dbParams[] directly in my code, but I find it more helpful to give meaningful names to each of the values in the array. Is there a way I can get all the results directly, without going through the array?
I am looking for something like:
db.ReadParams(memberID, product, out _memberCode, out _password, out _userName, out _reasonCode);
or
Tuple<_memberCode, _password, _userName, _reasonCode> = db.ReadParams(memberID, product);
Of course, it has to be legal C# code :)
You are writing code in a highly object oriented language, so why don't you use objects?
Member m = db.ReadParams(memberID, product, GetSubscriptionFields());
and in your code you use
m.memberCode
m.password
m.username
m.reasonCode
Of course you don't have to make the values publicly accessible, you can make them only accessible via setter/getter methods, and by only having getters, you can avoid them from being altered after object creation.
Of course different calls to db.ReadParams should return different objects, e.g. you can create an abstract base class and inherit all possible results from db.ReadParams of it. Therefor you may have to encapsulate db.ReadParams into another method that finds out the right type of object to create:
ReadParamsResult rpr = myDb.ReadParamsAsObject(memberID, product, GetSubscriptionFields());
// Verify that the expected result object has been returned
Debug.Assert(rpr is Member);
// Downcast
Member m = (Member)rpr;
Why not use constants instead?
Then in your code you could have
dbParams[MEMBER_CODE]
dbParams[PASSWORD]
dbParams[USERNAME]
dbParams[REASON_CODE]
which meets your goal of meaningful names without changing the way the method works.
I think your Tuple idea is pretty good. You could define it like this:
public class Tuple<T1, T2, T3, T4>
{
public T1 Field1 { get; set; }
public T2 Field2 { get; set; }
public T3 Field3 { get; set; }
public T4 Field4 { get; set; }
}
You would probably want to define a few of those, with two and three properties. Unfortunately it doesn't help you naming the properties of the class. There really is no way to do that (at least not until C# 4.0, when you could use dynamic typing with an anonymous type.
Not really; since the number of arguments isn't fixed, there isn't really a better way of doing it. The problem with regular tuples is that you are still working positionally - just with ".Value0" instead of "[0]". And anonymous types can't be directly exposed in an API.
Of course, you could subsequently wrap the values in your own class with properties, and just do a projection:
return new Foo {MemberCode = arr[0], ...}
(where Foo is your class that represents whatever this result is, with named, typed properties)
Alternatively you could throw them into a dictionary, but this doesn't help the caller any more than an array does.
The only other option is something really grungy like accepting a params array of Action<string> that you use to assign each. I'll elaborate on the last just for fun - I don't suggest you do this:
static void Main()
{
string name = "";
int value = 0;
Foo("whatever",
x => { name = x; },
x => { value = int.Parse(x); });
}
// yucky; wash eyes after reading...
static void Foo(string query, params Action<string>[] actions)
{
string[] results = Bar(query); // the actual query
int len = actions.Length < results.Length ? actions.Length : results.Length;
for (int i = 0; i < len; i++)
{
actions[i](results[i]);
}
}
I also came up with this... I kinda like it most, but it's a personal preference, I understand it's definitely not the cleanest idea:
using System.Diagnostics;
public static class ArrayExtractor
{
public static void Extract<T1>(this object[] array, out T1 value1)
where T1 : class
{
Debug.Assert(array.Length >= 1);
value1 = array[0] as T1;
}
public static void Extract<T1, T2>(this object[] array, out T1 value1, out T2 value2)
where T1 : class
where T2 : class
{
Debug.Assert(array.Length >= 2);
value1 = array[0] as T1;
value2 = array[1] as T2;
}
}
Of course, I am extending this class up to 10 or 15 arguments.
Usage:
string fileName;
string contents;
ArrayExtractor.Extract(args, out fileName, out contents);
or even better
args.Extract(out fileName, out contents);
where args is, of course, an object array.
Related
I want to create methods which are able to convert lists to tuples (or a struct) by matching types.
I would also need to create overloads for several tuple component counts so I could for example call:
var t1 = GetAsTuple<(HealthComponent)>(components);
var t2 = GetAsTuple<(PositionComponent, ModelComponent)>(components);
var t3 = GetAsTuple<(Texture, ModelComponent, PositionComponent)>(components);
Since I have lots of combinations of these I call them component-tuples I want to avoind lots of boilerplate code and want a generic mechanism to fill these tuples.
This is what I tried, obviously it does not compile:
public T GetAsTuple<T>(Component[] components)
where T : ValueTuple<x, y>, new()
where x : Component
where y : Component
{
var t = new T();
t.Item1 = components.OfType<x>().Single();
t.Item2 = components.OfType<y>().Single();
return t;
}
Is it possible what I am trying to do or is there another way to get the desired behavior.
I know that I could reach what Iam trying to do with reflection, but this is too slow for the context (game development).
A solution to get these Tuples as you've specified would actually require many, very similar methods. If you look into the .Net source code you'll see that this is actually how the Tuple.Create method works:
var t1 = GetAsTuple<HealthComponent>(components);
var t2 = GetAsTuple<PositionComponent, ModelComponent>(components);
var t3 = GetAsTuple<Texture, ModelComponent, PositionComponent>(components);
public Tuple<T1> GetAsTuple<T1>(Component[] components)
=> Tuple.Create(components.GetComponent<T1>());
public Tuple<T1, T2> GetAsTuple<T1, T2>(Component[] components)
=> Tuple.Create(components.GetComponent<T1>(),
components.GetComponent<T2>());
public Tuple<T1, T2, T3> GetAsTuple<T1, T2, T3>(Component[] components)
=> Tuple.Create(components.GetComponent<T1>(),
components.GetComponent<T3>(),
components.GetComponent<T2>());
... etc ...
// I would still use this extension
public static class ComponentExtensions
{
public static T GetComponent<T>(this Component[] components)
{
return components.OfType<T>().Single(); // note this will throw if 0 or more than 1 are in the array.
}
}
For now I will stick with a reflection based solution.
When I have the time I will implement a T4-template which generates the method overloads for me.
You could have a much simpler method to get the specific component:
public static class ComponentExtensions
{
public static T GetComponent<T>(this Component[] components)
{
return components.OfType<T>().Single(); // note this will throw if 0 or more than 1 are in the array.
}
}
Then I expect you'd have classes that deal with specific things and need certain components:
public class SomethingDoer
{
private readonly PositionComponent _position;
private readonly ModelComponent _model;
public SomethingDoer(Component[] components)
{
_position = components.GetComponent<PositionComponent>();
_model = components.GetComponent<ModelComponent>();
}
public void DoSomething()
{
...
}
I'm having trouble getting and setting the values of an item in a bindinglist with coordinates when the type vary.
For example, let's say I have three classes:
public class Client{
public string Name{ get; set; }
}
public class Debt{
public string AccountType{ get; set; }
public int DebtValue { get; set; }
}
public class Accounts{
public string Owner{ get; set; }
public int AccountNumber { get; set; }
public bool IsChekingAccount { get; set; }
}
and then, three bindinglists (imagine they are populated):
public BindingList<Client> listOne;
public BindingList<Debt> listTwo;
public BindingList<Accounts> listThree;
I'm trying to create an extension method that returns an Object with the value requested, or sets the value if it is provided.
public static Object GetValueByCoordinates(this IBindingList list, int x, int y) { /*some magic*/ }
public static Object SetValueByCoordinates(this IBindingList list, int x, int y, Object value) { /*some other magic*/ }
So, for instance, I need to be able to set the value of the item (2,3) in the listThree, and the value (1,1) in listTwo:
listThree.SetValueByCoordinates(2,3,false);
listThree.SetValueByCoordinates(1,1,"My self");
or get the value (1,1) and (2,2) from listOne and listTwo:
string result = listOne.GetValueByCoordinates(1,1).ToString();
intresult = Convert.ToInt32(listOne.GetValueByCoordinates(1,1));
How would you achieve such behavior? i was thinking of using reflection, but I know little to nothing about it.
please note that the methods MUST be called that way, so using something like this must be avoided
public static Object GetValueByCoordinates<T>(this BindingList<T> list, int x, int y) { /*some magic*/ }
Any help will be appreciated.
As mentioned, I am very skeptical that the approach you're asking for help with is likely to be the best or most appropriate way to address whatever the broader issue you're trying to solve is. It can be done (and without very much difficulty), but the resulting code is difficult to maintain, error-prone, and not very readable (which leads to the first two problems).
That said, there are lots of different ways to implement the specific behavior you're asking for. And even if this is not the best way to solve your current problem, the basic techniques are useful to know for other types of problems. With that in mind, here are two of the most obvious ways you might address your problem.
Manually configure a mapping from indexes to getters and setters:
IMHO this is the most preferable way. Not because it's elegant or easy to extend, but specifically because it's not either of those things. Requiring code maintainers to explicitly create the data structure elements to support each type and property that you want to handle will discourage a proliferation of this technique for other related problems, and even for the current problem. It could even encourage someone to spend a little more time thinking about the broader problem so as to find a better strategy.
This approach does have the advantage that it is reasonably performant. Because the code is generated at compile time, the only real overhead is the boxing that occurs for value types. There's some casting but for the reference types that overhead should be practically unmeasurable, and even the boxing overhead may not show up on a profile, depending on how intensively this code might be used.
This particular solution looks like this:
static class ManualIndexedProperty
{
public static void SetValueByCoordinates(this IBindingList list, int x, int y, object value)
{
object o = list[x];
_typeToSetter[o.GetType()][y](o, value);
}
public static object GetValueByCoordinates(this IBindingList list, int x, int y)
{
object o = list[x];
return _typeToGetter[o.GetType()][y](o);
}
private static readonly Dictionary<Type, Func<object, object>[]> _typeToGetter =
new Dictionary<Type, Func<object, object>[]>()
{
{
typeof(Client),
new Func<object, object>[]
{
o => ((Client)o).Name
}
},
{
typeof(Debt),
new Func<object, object>[]
{
o => ((Debt)o).AccountType,
o => ((Debt)o).DebtValue,
}
},
{
typeof(Accounts),
new Func<object, object>[]
{
o => ((Accounts)o).Owner,
o => ((Accounts)o).AccountNumber,
o => ((Accounts)o).IsChekingAccount,
}
},
};
private static readonly Dictionary<Type, Action<object, object>[]> _typeToSetter =
new Dictionary<Type, Action<object, object>[]>()
{
{
typeof(Client),
new Action<object, object>[]
{
(o1, o2) => ((Client)o1).Name = (string)o2
}
},
{
typeof(Debt),
new Action<object, object>[]
{
(o1, o2) => ((Debt)o1).AccountType = (string)o2,
(o1, o2) => ((Debt)o1).DebtValue = (int)o2,
}
},
{
typeof(Accounts),
new Action<object, object>[]
{
(o1, o2) => ((Accounts)o1).Owner = (string)o2,
(o1, o2) => ((Accounts)o1).AccountNumber = (int)o2,
(o1, o2) => ((Accounts)o1).IsChekingAccount = (bool)o2,
}
},
};
}
Two dictionaries are declared, one each for setting and getting property values. The dictionaries map the element object's type to an array of delegate instances to perform the actual work. Each delegate instance references an anonymous method which has been hand-coded to perform the necessary operation.
One major advantage to this approach is that it is explicit and obvious what index corresponds to what property for each type.
This approach will be tedious and time-consuming to set up if you are dealing with any significant number of types and/or properties. But IMHO that's a good thing. As I noted above, hopefully the pain of this approach can help convince someone to abandon the idea of accessing the properties by index altogether. :)
If this kind of tedium is unacceptable and yet you still insist on the indexed-property-access approach, then you can in fact use reflection as an alternative…
Use reflection to access the properties:
This technique is more dynamic. Once implemented, it works for any type object without modification, and does not require additional work to support new types.
One major disadvantage is that in order to produce consistent, predictable results, it sorts the properties by name. This ensures that changes in the C# compiler and/or CLR won't break the code, but it means you can't add or remove properties from a type without updating the code that is accessing those properties by index.
In my demo usage code (see further below), I address this maintenance issue by declaring enum types that provide int values for property names. This would be a good way to help reduce the maintenance overhead if the code is actually referring to the properties with literal index values.
However, it's possible your scenario involves dynamically accessing the property values by index, e.g. in a serialization scenario or similar. In that case, you will also need to add something that can remap or otherwise deal with changes in the index values should properties be added or removed to the types.
Frankly, either way this issue of the types indexes changing is one big reason I'd strongly recommend against this indexed access to properties in the first place. But again, if you insist…
static class ReflectionIndexedProperty
{
public static void SetValueByCoordinates(this IBindingList list, int x, int y, object value)
{
object o = list[x];
GetProperty(o, y).SetValue(o, value);
}
public static object GetValueByCoordinates(this IBindingList list, int x, int y)
{
object o = list[x];
return GetProperty(o, y).GetValue(o);
}
private static PropertyInfo GetProperty(object o, int index)
{
Type type = o.GetType();
PropertyInfo[] properties;
if (!_typeToProperty.TryGetValue(type, out properties))
{
properties = type.GetProperties();
Array.Sort(properties, (p1, p2) => string.Compare(p1.Name, p2.Name, StringComparison.OrdinalIgnoreCase));
_typeToProperty[type] = properties;
}
return properties[index];
}
private static readonly Dictionary<Type, PropertyInfo[]> _typeToProperty = new Dictionary<Type, PropertyInfo[]>();
}
In this version, the code retrieves the array of PropertyInfo objects for a given type, sorts that array by name, retrieves the appropriate PropertyInfo object for the given index, and then uses that PropertyInfo object to set or get the property value, as appropriate.
Reflection incurs a significant run-time performance overhead. This particular implementation mitigates some of that overhead by caching the sorted arrays of PropertyInfo objects. That way, they only need to be created once, the first time the code has to handle an object of the given type.
Demo code:
As I mentioned, to make it easier to compare the two approaches without having to go to each method call and hand-change an integer literal used for the call, I created some simple enum types to represent the property indexes. I also wrote some code to initialize some lists that could be tested.
Note: one very important thing to point out is that in your question you were not very consistent about how you were indexing the properties. In my code example, I have chose to stick with a 0-based index (consistent with the natural indexing used in C# arrays and other collections). You can of course use a different base (e.g. 1-based indexing), but you will need to make sure you are entirely consistent throughout the code (including subtracting 1 from the passed-in index when actually indexing an array).
My demo code looks like this:
class Program
{
static void Main(string[] args)
{
BindingList<Client> listOne = new BindingList<Client>()
{
new Client { Name = "ClientName1" },
new Client { Name = "ClientName2" },
new Client { Name = "ClientName3" },
};
BindingList<Debt> listTwo = new BindingList<Debt>()
{
new Debt { AccountType = "AccountType1", DebtValue = 29 },
new Debt { AccountType = "AccountType2", DebtValue = 31 },
new Debt { AccountType = "AccountType3", DebtValue = 37 },
};
BindingList<Accounts> listThree = new BindingList<Accounts>()
{
new Accounts { Owner = "Owner1", AccountNumber = 17, IsChekingAccount = false },
new Accounts { Owner = "Owner2", AccountNumber = 19, IsChekingAccount = true },
new Accounts { Owner = "Owner3", AccountNumber = 23, IsChekingAccount = true },
};
LogList(listThree);
listThree.SetValueByCoordinates(2, (int)AccountsProperty.IsChekingAccount, false);
listThree.SetValueByCoordinates(1, (int)AccountsProperty.Owner, "My self");
LogList(listThree);
string result1 = (string)listOne.GetValueByCoordinates(0, (int)ClientProperty.Name);
int result2 = (int)listTwo.GetValueByCoordinates(1, (int)DebtProperty.DebtValue);
LogList(listOne);
LogList(listTwo);
Console.WriteLine("result1: " + result1);
Console.WriteLine("result2: " + result2);
}
static void LogList<T>(BindingList<T> list)
{
foreach (T t in list)
{
Console.WriteLine(t);
}
Console.WriteLine();
}
}
Note that I use simple casting to convert from object to the specific type, both with setting property values and getting them. This is a much better approach than e.g. calling ToString() or Convert.ToInt32(); you know exactly what the type is supposed to be, and it's either an actual instance of that type (for reference types) or a boxed instance (for value types), and either way a cast does exactly what you need.
I also added ToString() overrides to your example classes to make it easier to see the output:
public class Client
{
public string Name { get; set; }
public override string ToString()
{
return "{" + Name + "}";
}
}
public class Debt
{
public string AccountType { get; set; }
public int DebtValue { get; set; }
public override string ToString()
{
return "{" + AccountType + ", " + DebtValue + "}";
}
}
public class Accounts
{
public string Owner { get; set; }
public int AccountNumber { get; set; }
public bool IsChekingAccount { get; set; }
public override string ToString()
{
return "{" + Owner + ", " + AccountNumber + ", " + IsChekingAccount + "}";
}
}
Finally, here are the enum declarations used:
Manual indexing:
enum ClientProperty
{
Name = 0
}
enum DebtProperty
{
AccountType = 0,
DebtValue = 1
}
enum AccountsProperty
{
Owner = 0,
AccountNumber = 1,
IsChekingAccount = 2,
}
Reflection/sorted by name:
enum ClientProperty
{
Name = 0
}
enum DebtProperty
{
AccountType = 0,
DebtValue = 1
}
enum AccountsProperty
{
AccountNumber = 0,
IsChekingAccount = 1,
Owner = 2,
}
Of course, these could both have been the same values. That is, while you don't have control over the sort order, once the property names are given, the manual version could have declared the manually-written lambdas in sorted-by-name order so that the same indexes would have worked either way. It doesn't matter too much what you decide to do; it just has to be consistent.
Final thoughts…
Have I mentioned yet how strongly I would recommend against building any significant amount of code around this technique? It's not at all clear what your actual bigger-picture problem you're trying to solve is, but there are just a lot of different ways for this to go wrong, and it is likely to lead to lots of hard-to-find, time-consuming-to-fix bugs in the code.
In terms of performance, the above should not be too bad as long as you are not executing the code in a tight loop for huge numbers of objects and property values. The manual (first) example in particular should be relatively fast. It is possible to achieve the generalized design of the reflection-based approach with the minimal overhead of the manual approach by using the Expression type. That's a bit more complicated, but would have the advantage that you can generate expressions dynamically that wind up being effectively the compiled-code implementation of the manual approach.
I think this question was asked many times in C# but my problem is maybe more solvable.
I have an object value as a string : myobject.value and I want to store this value in a queue (or anything else) to access it later. Is it possible?
I read a lot of posts saying that it is not possible to store a ref to a string.
I don't see any solution to store a ref to my string value myobject.value and change it later.
Any Ideas ?
If you want to store a reference to a string that people can see and share the changes of you will need to wrap it in a class:
public class Wrapper<T>
{
public T Item { get; set; }
}
Then people use this instead of a string:
class MyClass
{
public Wrapped<string> SharedString { get; set; }
}
var c1 = new MyClass();
var c2 = new MyClass();
var s = new Wrapped<string> { Item = "Hello" };
c1.SharedString = s;
c2.SharedString = s;
c1.SharedString.Item = "World";
Console.Writeline(c2.SharedString.Item);
Even though strings are reference types, they are immutable so changes need to the "copied" around. Sharing is this way doesn't change the immutability, it just centrally holds one copy of a string that everyone is looking at via their reference to Wrapped<string>.
You can take the Wrapped<T> class further and give it implicit cast support to and from T, for a little syntactic sugar:
public static implicit operator T(Wrapped<T> wrapper)
{
return wrapper.Item;
}
public static implicit operator Wrapped<T>(T item)
{
return new Wrapped<T> { Item = item };
}
Wrapped<int> i = 2;
int j = i;
// Careful, this is a re-assignment of s, not a change of s.Item.
Wrapped<string> s = "Hello";
If I understand you right, and myobject.value is a string, than you can certainly store a collection representing those values
List<string> strLst = new List<string>();
strLst.Add(`myobject.value`);
No, you can't store a reference as a string, nor should you have to, but you can make a string(or xml) that represents all the information about your object, if you really need to.
Hii
I have method in C#, I have to return multiple values from that method with out using collections like arrays. Is there any reliable way ?
Yes, the out keyword:
public void ReturnManyInts(out int int1, out int int2, out int int3)
{
int1 = 10;
int2 = 20;
int3 = 30;
}
then call it like this:
int i1, i2, i3;
ReturnManyInts(out i1, out i2, out i3);
Console.WriteLine(i1);
Console.WriteLine(i2);
Console.WriteLine(i3);
which outputs:
10
20
30
EDIT:
I'm seeing that a lot of posts are suggesting to create your own class for this. This is not necessary as .net provides you with a class to do what they are saying already. The Tuple class.
public Tuple<int, string, char> ReturnMany()
{
return new Tuple<int, string, char>(1, "some string", 'B');
}
then you can retrieve it like so:
var myTuple = ReturnMany();
myTuple.Item1 ...
myTuple.Item2 ...
there are generic overloads so you can have up to 8 unique types in your tuple.
Well, you could use:
a custom class/struct/type, containing all your values
out parameters
I.e.:
class MyValues
{
public string Val1 { get; set; }
public int Val2 {get; set; }
}
public MyValues ReturnMyValues();
or
public void ReturnMyValues(out string Val1, out int Val2);
If you are using .NET 4.0 you can use one of the generic Tuple classes to return multiple values from a method call. The static Tuple class provides methods to create Tuple objects. So you do not have to define your own return type for the method.
public Tuple<string,int> Execute()
{
return new Tuple<string,int>("Hello World", 2);
}
Yes could create a new type that will contain multiple properties and then return this type:
public MyType MyMethod()
{
return new MyType
{
Prop1 = "foo",
Prop2 = "bar"
};
}
Why should using 'out' being an unreliable way? (Or did you make a typo and meant without?)
There are several methods:
Return a object which holds multiple
values (struct/class etc)
out
ref
A Descriptor class, or structure. You must put it somewhere as it's logical that a method must return only one value. Alternatively you can use out or ref, but i would go returning a class.
Btw what's holding you not to use collections?.
public int Method Name(out string stringValue, out int intValue)
{
///
Method goes here
///
return intVaraible
}
here you will get 3 return Values
1. stringValue
2. intValue
3. intVariable
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