473,387 Members | 1,493 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

Generic issue

Airslash
221 100+
Hi,

I think i've asked this before, but never gotten to a concrete solution....

Say I have a class Table. This class as a List of type Filter that is a generic type. The filter class looks like this :

Expand|Select|Wrap|Line Numbers
  1. abstract public class Filter<T>
  2.     {
  3.         /// <summary>
  4.         /// Creates a new TableFilter that can be applied to a Table object.
  5.         /// </summary>
  6.         /// <param name="Column">The column to apply the filter on.</param>
  7.         /// <param name="Criteria">The criteria of the filter to apply.</param>
  8.         public Filter(String column, params T[] criteria)
  9.         {
  10.             Column = column;
  11.             Criteria = criteria;
  12.         }
  13.  
  14.         /// <summary>
  15.         /// Gets or sets the name of the column to apply the Criteria filter on.
  16.         /// </summary>
  17.         public String Column
  18.         {
  19.             get { return m_column; }
  20.             set { m_column = value; }
  21.         }
  22.  
  23.         /// <summary>
  24.         /// Gets or sets the Criteria to apply to the selected column.
  25.         /// This Criteria needs to match the Syntax of SQL.
  26.         /// To supplie multiple values, seperate the values with a ;
  27.         /// </summary>
  28.         public T[] Criteria
  29.         {
  30.             get { return m_criteria; }
  31.             set { m_criteria = value; }
  32.         }
  33.  
  34.         private String m_column;    // The column to apply the filter on.
  35.         private T[] m_criteria;     // The criteria of the filter.
  36.     }
  37.  
So now in my Table class, I wish to store a List of Filters. The only problem is that this List should be able to carry Filters of different types at any given time. Meaning I need to be able to store filters like this:

- Filter<int>("name", value)
- Filter<string>("name", value)
- Filter<bool>("name", value)

I've designed my class Table like this:

Expand|Select|Wrap|Line Numbers
  1.  
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Data;
  5. using System.Data.Common;
  6. using System.Linq;
  7. using System.Text;
  8. using NexusDB.ADOProvider;
  9. using NexusLink.r9_4.Filters;
  10.  
  11. namespace NexusLink.r9_4
  12. {
  13.     public abstract class Table
  14.     {
  15.         /// <summary>
  16.         /// Creates a new instance of the table with the given name and uses the default
  17.         /// settings to establish a connection to the database.
  18.         /// </summary>
  19.         /// <param name="name">The name of the table to map on.</param>
  20.         public Table(String name) : this(name, new DatabaseSettings()) { }
  21.  
  22.         /// <summary>
  23.         /// Creates a new instance of the table with a given name and the specified settings
  24.         /// to establish a connection to the database.
  25.         /// </summary>
  26.         /// <param name="name">The name of the table to map on.</param>
  27.         /// <param name="settings">The settings to establish a connection to the database.</param>
  28.         public Table(String name, DatabaseSettings settings)
  29.         {
  30.             Name = name;
  31.             m_command = DbProviderFactories.GetFactory("NexusDB.ADOProvider").CreateCommand();
  32.             m_connection = DbProviderFactories.GetFactory("NexusDB.ADOProvider").CreateConnection();
  33.             m_reader = null;
  34.             m_filters = new List<Filter<T>>();
  35.             m_lock = new object();
  36.             Settings = settings;
  37.  
  38.             // Configure the command and the connection.
  39.             m_command.Connection = m_connection;
  40.         }
  41.  
  42.         /// <summary>
  43.         /// Gets the name of the table.
  44.         /// </summary>
  45.         public String Name
  46.         {
  47.             get { return m_name; }
  48.             protected set { m_name = value; }
  49.         }
  50.  
  51.         /// <summary>
  52.         /// Gets or sets the settings for the table and the database connection.
  53.         /// </summary>
  54.         public DatabaseSettings Settings
  55.         {
  56.             get { return m_settings; }
  57.             set { m_settings = value; }
  58.         }
  59.  
  60.         /// <summary>
  61.         /// Adds a new filter to the table.
  62.         /// </summary>
  63.         /// <param name="filter">The filter to add to the table.</param>
  64.         public void AddFilter(Filter<object> filter)
  65.         {
  66.             lock (m_lock)
  67.             {
  68.                 m_filters.Add(filter);
  69.             }
  70.         }
  71.  
  72.         /// <summary>
  73.         /// Removes all the filters currently placed on the table.
  74.         /// </summary>
  75.         public void ClearFilters()
  76.         {
  77.             lock (m_lock)
  78.             {
  79.                 m_filters.Clear();
  80.             }
  81.         }
  82.  
  83.         /// <summary>
  84.         /// Advances the table to the next row in the result set.
  85.         /// </summary>
  86.         /// <returns>True if the next row is available; otherwise false.</returns>
  87.         public bool Next()
  88.         {
  89.             // Obtain a lock on the table for exclusive access.
  90.             lock (m_lock)
  91.             {
  92.                 // Advance the datareader.
  93.                 return m_reader.NextResult();
  94.             }
  95.         }
  96.  
  97.         /// <summary>
  98.         /// Returns the current row containing data.
  99.         /// </summary>
  100.         /// <returns>A TableRow object holding the data.</returns>
  101.         public TableRow GetCurrentRow()
  102.         {
  103.             throw new NotImplementedException();
  104.         }
  105.  
  106.         /// <summary>
  107.         /// Opens the connection to the database and retrieves the data for the
  108.         /// table based upon the filters set on the table.
  109.         /// </summary>
  110.         /// <returns>True if the connection was successfully established; otherwise false</returns>
  111.         public bool Open()
  112.         { 
  113.             // Obtain a lock on our lockable object so we have exclusive access to the
  114.             // table object and the internals.
  115.             lock (m_lock)
  116.             {
  117.                 // Configure the Connection object to connect to the database with
  118.                 // the settings that have been applied to our table object.
  119.                 m_connection.ConnectionString = m_settings.ToString();
  120.  
  121.                 // Now we need to configure the command object to select the table from the
  122.                 // the table we're representing. The selection of the data depends on the filters
  123.                 // that have been applied to our table.
  124.                 if (m_filters.Count > 0)
  125.                 {
  126.                     // Filters have been applied to the Table. Create the statement including
  127.                     // the filters.
  128.                     m_command.CommandText = String.Format("SELECT * FROM {0} WHERE ", Name);
  129.  
  130.                     // Add all the filters.
  131.                     foreach (Filter<object> f in m_filters)
  132.                     {
  133.                         // Add the filter, and add " AND " if it's not the last filter.
  134.                         if (m_filters.IndexOf(f) == (m_filters.Count - 1)) m_command.CommandText += f.ToString();
  135.                         else m_command.CommandText += f.ToString() + " AND ";
  136.                     }
  137.  
  138.                     // Add the final ;
  139.                     m_command.CommandText += ";";
  140.                 }
  141.                 else
  142.                 {
  143.                     // No filters have been applied on the table, so just select the
  144.                     // raw data from the table.
  145.                     m_command.CommandText = String.Format("SELECT * FROM {0};", Name);
  146.                 }
  147.  
  148.                 // Now that the SQL Code has been generated, apply the last settings to the Command.
  149.                 m_command.CommandType = CommandType.Text;
  150.                 m_command.CommandTimeout = 10000;
  151.  
  152.                 // Surround the entire connection attempt with a try-catch statement to prevent
  153.                 // errors from breaking the code.
  154.                 try
  155.                 {
  156.                     // Open the connection.
  157.                     m_reader = m_command.ExecuteReader(CommandBehavior.CloseConnection);
  158.  
  159.                     // Return true because we suceeded.
  160.                     return true;
  161.                 }
  162.                 catch
  163.                 {
  164.                     // Could not establish a connection, return false.
  165.                     return false;
  166.                 }
  167.             }
  168.         }
  169.  
  170.         /// <summary>
  171.         /// Closes the connection to the database.
  172.         /// </summary>
  173.         public void Close()
  174.         { 
  175.             // Obtain a lock on our lockable object so we have exclusive access
  176.             // to our table object.
  177.             lock (m_lock)
  178.             {
  179.                 // Close the datareader first.
  180.                 m_reader.Close();
  181.  
  182.                 // Close the connection.
  183.                 m_connection.Close();
  184.             }
  185.         }
  186.  
  187.         /// <summary>
  188.         /// Inserts a new row into the table at the end with the specified values.
  189.         /// </summary>
  190.         /// <param name="row">The row to insert into the table.</param>
  191.         /// <returns>True if the row was successfully inserts; otherwise false.</returns>
  192.         public bool InsertRow(TableRow row)
  193.         {
  194.             throw new NotImplementedException();
  195.         }
  196.  
  197.         private String m_name;
  198.         private List<Filter<object>> m_filters;
  199.         private DatabaseSettings m_settings;
  200.         private IDbCommand m_command;
  201.         private IDbConnection m_connection;
  202.         private IDataReader m_reader;
  203.         private object m_lock;
  204.     }
  205. }
  206.  
I've tried setting the base class to object for the type but that's not working. Getting conversion errors when I call the code with the various types.

Is there a way around this, that I can have 1 List<Filter<something>> as datamember that allows me to store multiple Filter types?

I can't make the table class Generic, as that serves no purpose in the design.
Jun 30 '10 #1
6 1614
GaryTexmo
1,501 Expert 1GB
You can always use the base type, object, for your list.

List<Filter<object>> should be able to store anything you like.
Jun 30 '10 #2
Airslash
221 100+
I've tried that, but when I code a second class and for example try to add 'new Filter<int>("ID", 0);' I get an error from the compiler that new Filter<int> cannot be cast to new Filter<object>
Jun 30 '10 #3
GaryTexmo
1,501 Expert 1GB
Ah, you're right! Sorry about that... it's a little more complicated than I thought :D

I played around and here's something that might work for you...

Expand|Select|Wrap|Line Numbers
  1.     class Program
  2.     {
  3.         static void Main(string[] args)
  4.         {
  5.             List<object> myList = new List<object>();
  6.             myList.Add(new Container<int>(5));
  7.             myList.Add(new Container<string>("blah"));
  8.  
  9.             foreach (object o in myList)
  10.             {
  11.                 Type objType = o.GetType();
  12.                 object data = objType.InvokeMember("Data", System.Reflection.BindingFlags.GetProperty, null, o, null);
  13.                 Console.WriteLine(data);
  14.             }
  15.         }
  16.     }
  17.  
  18.     public class Container<T>
  19.     {
  20.         private T m_data;
  21.  
  22.         public Container(T data)
  23.         {
  24.             m_data = data;
  25.         }
  26.  
  27.         public T Data
  28.         {
  29.             get { return m_data; }
  30.             set { m_data = value; }
  31.         }
  32.     }
I vaguely recalled InvokeMember from something I did a while back, but you might want to do some research on it. Use that code as a guideline more than anything.

The general idea though is that you store your filters in a list of objects. You lose your type info at this point though so you can't call methods on your Filter. However, we can use reflection to make the call. The parameters I used were ones that just made sense for the call I was making... the name of the method, null for the default binder, the object we're calling the method on, and null for no parameters since there aren't any for the property.

This me run the method and get the return. I put it into an object since in my example, it could be anything and I only want the ToString method on it anyway, which is part of object. You could do more reflection if you needed other methods and didn't know the type.

Give that a try :)
Jun 30 '10 #4
Airslash
221 100+
I've came up with something similar I guess :)

I'm boxing the values I recieve from the database into raw objects as well for my TableRowField classes and perform the casts as required.

Made a specific Row object for each table at the moment and supplied properties to cast them to the correct type depending on the column name.

Not the ideal solution, but it's working for now.

In the future i'm definitly implementing a self-aware component through reflection.

Thanks for the tips though, I'm sure they'll come in handy :)
Jun 30 '10 #5
Christian Binder
218 Expert 100+
If you'd use C# 4.0 this would be possible, because it supports covariance.

Have a look at http://msdn.microsoft.com/en-us/library/dd799517.aspx
Jul 1 '10 #6
Airslash
221 100+
that looks sweet.
We're jumping on .NET 4.0 soon probably due the switch to VS2010
Jul 1 '10 #7

Sign in to post your reply or Sign up for a free account.

Similar topics

15
by: David Lozzi | last post by:
Howdy, I have a function that uploads an image and that works great. I love ..Nets built in upload, so much easier than 3rd party uploaders! Now I am making a public function that will take the...
8
by: JAL | last post by:
Here is my first attempt at a deterministic collection using Generics, apologies for C#. I will try to convert to C++/cli. using System; using System.Collections.Generic; using System.Text; ...
0
by: Wiktor Zychla [C# MVP] | last post by:
We do have generic classes, methods and delegates. My question is: what reason prevents us from having generic properties and indexers? // impossible public List<T> GetList<T> { get { ... }
25
by: Lars | last post by:
Hi, I have a base class holding a generic list that needs to be accessed by both the base class and its subclasses. What is the best solution to this? I am fairly new to generics, but I am...
3
by: Tigger | last post by:
I have an object which could be compared to a DataTable/List which I am trying to genericify. I've spent about a day so far in refactoring and in the process gone through some hoops and hit some...
14
by: James Wong | last post by:
Hi everybody, I'm facing a serious trouble relating to GDI+ generic error. The error message is "A Generic error occured in GDI+" and the following information is stored in Excepton object:...
1
by: Suds | last post by:
Hi, I'm having an issue with invoking a Generic method that takes Generic Arguments. My method signature is public void GenericMethodWithGenericArguments<E, V>(List<EtheFirstList,...
9
by: Steve Richter | last post by:
in a generic class, can I code the class so that I can call a static method of the generic class T? In the ConvertFrom method of the generic TypeConvert class I want to write, I have a call to...
9
by: tadmill | last post by:
Is it possible to pass a generic parameter of the same class to to its constructor, where the "T" type passed in the constructor is different than the "T" type of the instanced class? ie, ...
8
by: MMAS | last post by:
Hey everyone -- Curious about some strange behaviour I'm seeing that seems to be related to my lack of understanding on how generics work in C#. Here's some simplified code (sorry for strange...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.