I'm busy building a custom framework for data retrieval and serialization and I'm running into a problem when defining a proprietary database connection/command/parameter combo. Everything works as expected until I try and add parameters to my custom command object. I have a base class that handles query preparation and execution with a generic function as follows:
/// <summary>
/// Prepares a command for execution.
/// </summary>
/// <typeparam name="C">The type of command to prepare</typeparam>
/// <typeparam name="P">The type of parameters to add to the command</typeparam>
/// <param name="query">The query to be prepared for the command</param>
/// <param name="parameters">Dictionary of parameters to be added to the command</param>
/// <returns>A prepared command to execute against a database</returns>
protected virtual C Prepare<C, P>(string query, Dictionary<string, object> parameters)
where C : DbCommand, new()
where P : DbParameter, new()
{
if (Connection == null)
throw new System.Exception("Database connector hasn't been initialized yet. Call .Initialize() first.");
C command = new C()
{
CommandText = query,
Connection = Connection
};
if (parameters != null)
{
foreach (KeyValuePair<string, object> kvp in parameters)
{
command.Parameters.Add(new P() // <-- Breaks right here!
{
ParameterName = kvp.Key,
Value = kvp.Value
});
}
parameters = null;
}
return command;
}
I have classes implemented for most of the provider types (Ole, ADO, ODBC, Oracle, etc), but they are based off the standard .NET types provided in the System.Data namespace. I now have a completely custom class that inherits from System.Data.Common.DbCommand that I want to use, but when I try and add parameters (in the Prepare function above) to this new class, I see the Parameters property of my new class is null! It is inherited from the base class and is set to read only, so I can't initialize it on my own. My class is defined as follows:
public sealed class Connection : System.Data.Common.DbConnection
I've tried explicitly overriding the property in my class as public new List<Parameter> Parameters { get; set; } but to no avail - the generic function still uses the base class' Parameters property. The only way to get a handle on the overridden property is to explicitly cast command (in the Prepare function) to my custom type, which is obviously what I don't want to do.
Am I missing something here?
First, new doesn't override the parameter, it's hiding it. This means that anyone using DbCommand.Parameters will see the original implementation while anyone using your type will see your implementation.
Overriding a property can only be done using the override keyword. In this case, you can't override Parameters because it isn't virtual.
Second, DbCommand.Parameters is just an external interface over the protected abstract DbCommand.DbCommandParameterCollection property. You need to implement this method to return a actual parameter collection.
OK, I managed to sort out the issue. Can't believe I've been blind to this the whole morning! When implementing a new class that inherits from System.Data.Common.DbCommand you have to override the DbParameterCollection property, among others. In my haste to create the new class I just returned null in the getter of this property and, I assume, that's what the Parameters property uses.
So I just implemented a new class that inherits from System.Data.Common.DbParameterCollection and returned a new instance of that class in my getter and it's working now!
Related
Using generic types is nice and easy, but since I tried to implement my own generic types, I came to a problem which I couldn't solve by myself yet. I want to have a static field for a delegate. This is how it works for me when using non-generic types:
delegate Type Type_Delegate(Type type);
static Type_Delegate TypeMethod = new Type_Delegate(TypeMethodName);
// Now the TypeMethod can be called like this from somewhere in the Code:
ClassName.TypeMethod(typeof(string));
But when using any generic type:
delegate T Type_Delegate<T>(T type);
// This static field syntax isn't allowed:
static Type_Delegate<T> TypeMethod = new Type_Delegate<T>(TypeMethodName);
// It would be a dream to be able to use it like this now:
ClassName.TypeMethod<string>("Hello world!");
T is unknown type/namespace.
When I experiment with the syntax:
// This static field syntax isn't allowed, too:
static Type_Delegate TypeMethod = new Type_Delegate(TypeMethodName);
Type arguments are missing for usage.
I tried several ideas about the possible syntax, but not succeed...
How do I need to change the static field syntax to work as assumed, so the code is able to set a generic delegate method as value, without having to specify a type at that time?
Edit: I also tried to wrap the delegate and field with a generic static class, but there I still have the same syntax issues, when I want to set the field value without specifying the type.
Edit 2: Maybe the following example workaround apporach will clarify my thoughts more, since I think most commenters didn't understand my goal (maybe it's my bad English, too):
using System;
using System.Linq;
using System.Reflection;
namespace Testing
{
public static class GenericTest
{
public interface IGenericClass<T>
{
T Method(T parameter);
}
public class GenericClass<T> : IGenericClass<T>
{
public T Method(T parameter)
{
// Just a stupid example, don't think about that...
return parameter;
}
}
/// <summary>
/// The value must be any type that implements the IGenericClass<T> interface
/// </summary>
public static Type GenericField = typeof(GenericClass<>);
/// <summary>
/// Call the method of an instance of the type that was set to GenericField
/// </summary>
/// <param name="T">The type to use for creating an instance of the generic class</param>
/// <param name="parameter">The parameter for calling the method of the generic class</param>
/// <returns>Any value of type "T"</returns>
public static dynamic GenericMethod(Type T, object parameter)
{
var genericType = GenericField.MakeGenericType(new Type[] { T });
MethodInfo method = genericType.GetMethod("Method");
if (method == null) throw new InvalidCastException("GenericField isn't a IGenericClass<T> type");
return method.Invoke(Activator.CreateInstance(genericType), new object[] { parameter });
}
}
}
Now I can do something like this somewhere else in the code:
MessageBox.Show(Testing.GenericTest.GenericMethod(typeof(string), "Hello world!"));
In this example solution I need to work with classes and an interface, require reflections, it's a whole bunch of code required to get the same functionality for a generic (class-)method, as I can get with only two lines of code when working with non-generic methods (using delegates). What an overhead, what a hack - I try to avoid doing such nasty things in productive code. But if there are no better 2 lines of Code that do the same, this time I will have to fight my ego...
It is possible, by wrapping it in a generic class definition and using the class type parameter.
static class C<T>
{
public static DelegateTypePrototype<T> DelegateType;
}
This way the type only has to be resolved once you "request" an instance of the class. At least that's my intuitive understanding coming from C++ templates background.
I am thinking of EF's DBContext and DBSets as the background to this question. You can access a particular set using the following code in a Repository class for example.
public TEntity Get(int id)
{
return Context.Set<TEntity>().Find(id);
}
Where Set<TEntity>() returns the set of type TEntity. How exactly is this coded? I tried to find the source code for it to no avail. Would I need to create my own classes and write the logic out in full?
TLDR: EF creates just a DbSet<T> entry in a dictionary where the the key is typeof(T).
Looking at the sourcecode it is implemented as following:
/// <summary>
/// Creates a <see cref="DbSet{TEntity}" /> that can be used to query and save instances of <typeparamref name="TEntity" />.
/// </summary>
/// <typeparam name="TEntity"> The type of entity for which a set should be returned. </typeparam>
/// <returns> A set for the given entity type. </returns>
public virtual DbSet<TEntity> Set<TEntity>()
where TEntity : class
=> (DbSet<TEntity>)((IDbSetCache)this).GetOrAddSet(DbContextDependencies.SetSource, typeof(TEntity));
And Line 195:
/// <summary>
/// This API supports the Entity Framework Core infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
object IDbSetCache.GetOrAddSet(IDbSetSource source, Type type)
{
CheckDisposed();
if (!_sets.TryGetValue(type, out var set))
{
set = source.Create(this, type);
_sets[type] = set;
}
return set;
}
Where sets is:
private readonly IDictionary<Type, object> _sets = new Dictionary<Type, object>();
I'm guessing Enumerable.OfType<TResult>() will come in handy here. It returns an IEnumerable<TResult> over all the elements of type TResult in the source enumeration. As for its implementation, MSDN has this to say:
This method is implemented by using deferred execution. The immediate return value is an object that stores all the information that is required to perform the action. The query represented by this method is not executed until the object is enumerated either by calling its GetEnumerator method directly or by using foreach in Visual C# or For Each in Visual Basic.
I don't know how EF does it, but you could easily accomplish something similar with a Dictionary keyed by Types
private Dictionary<Type, ICollection> registry = new Dictionary<Type, ICollection>();
// adds a collection of a certain type
public void Add<T>(T collection) where T: ICollection {
registry.Add(typeof(T), collection);
}
// create an empty collection of type T and add it to registry
public void InitCollection<T>() where T: ICollection {
registry.Add(typeof(T), (ICollection)Activator.CreateInstance(typeof(T)));
}
// returns a collection of type T if it has been registered
public T Set<T>() where T: ICollection {
return (T)registry[typeof(T)];
}
beginner:
want to write a method to return a generic collection as:
public IEnumerable<T> ABC( string x){
if( x== "1")
{ Collection<A> needs to be returned}
if(x=="2")
{ Collection<B> needs to be returned}
..
so on
}
Questions:
- based on "X" passed to the method different types of collections are initialized and need to be returned? how can i do that?
- is this the correct approach?
- any links to get more details on generic usages?
AFAIK, the type parameter (here T) must be known at compile time. Which means it can't change while running. What you could do is make it IEnumerable<Object>. Since every other type has Object as a base type, I'm pretty sure you could return an IEnumerable of anything at that point. Though you may need to cast in/out of Object on the way.
no need to pass string to identify the type of class .just call with the following generic method ,it will intialize the List of that T type.
/// <summary>
/// Gets the initialize generic list.
/// </summary>
/// <typeparam name="T"></typeparam>
public IList<T> GetInitializeGenericList<T>() where T : class
{
Type t = typeof(List<>);
Type typeArgs =typeof(T);
Type type = t.MakeGenericType(typeArgs);
// Create the List according to Type T
dynamic reportBlockEntityCollection = Activator.CreateInstance(type);
// If you want to pull the data into initialized list you can fill the data
//dynamic entityObject = Activator.CreateInstance(typeArgs);
//reportBlockEntityCollection.Add(entityObject);
return reportBlockEntityCollection;
}
I have a project I'm working on where I don't know what class I will need to instantiate at compile time. I'm trying to use Activator.CreateInstance() to generate a new class for me based on the user input. The code below works well, but I had to change my constructor on my INECCQuery classes to only have a default constructor and not use any sort of dependency injection. Is there a way I can still use my injection bindings and the Activator.CreatInstance()? I'm using Ninject for injection.
[HttpGet]
public ActionResult Index(string item) {
Type t = Type.GetType(string.Format("Info.Audit.Query.{0}Query, Info.Audit", item.ToUpper()));
if (t != null) {
INECCQuery query = (INECCQuery)Activator.CreateInstance(t);
var results = query.Check();
return View("Index", results);
}
return View("Notfound");
}
Constructor injection is always preferred where possible, but a suitable backup would be to leverage property injection.
http://ninject.codeplex.com/wikipage?title=Injection%20Patterns
class SomeController {
[Inject]
public Object InjectedProperty { get; set; }
}
Based on the assumption that you are trying to replace the Activator.CreateInstance you can inject a Func<T, INECCQuery> or whatever factory you wish to use.
You can get Ninject to give you an object of type t at runtime and still get the dependency injection via the constructor.... I do something similar for one case within my application.
In the Global.asax.cs file, I have the following method:
/// <summary>
/// Gets the instance of Type T from the Ninject Kernel
/// </summary>
/// <typeparam name="T">The Type which is requested</typeparam>
/// <returns>An instance of Type T from the Kernel</returns>
public static T GetInstance<T>()
{
return (T)Kernel.Get(typeof(T));
}
This depends on a static Kernel reference.
Then, in code, I do
var myInfrastructureObject = <YourAppNameHere>.GetInstance<MyInfrastructureType>();
So, I know the type at compile time whereas you don't, but it wouldn't be that difficult to change that.
You may also wish to look into the ServiceLocator Pattern.
I've actually found out you can just pass in a second option to the Activator.CreateInstance method and as long as it matches your constructors signature it will work. The only problem is if your parameters don't match you will get a runtime error.
Type t = Type.GetType(string.Format("Info.Audit.Query.{0}Query, Info.Audit", item.ToUpper()));
INECCQuery query = (INECCQuery)Activator.CreateInstance(t, repository);
Thanks for all the help.
I'm in the middle of overhauling some code and I hit a bit of a snag.
This is the method which I currently have, it needs reworking to support some structure changes:
/// <summary>
/// Recreates a dashboard control based off of its settings.
/// </summary>
/// <typeparam name="T"> The type of control to be recreated. </typeparam>
/// <param name="settings"> The known settings needed to recreate the control.</param>
/// <returns> The recreated control. </returns>
public static T Recreate<T>(ISetting<T> settings) where T : new()
{
T _control = new T();
settings.SetSettings(_control);
Logger.DebugFormat("Recreated control {0}", (_control as Control).ID);
return _control;
}
ISetting is being removed completely in favor of an extension method known to _control.
So, I have now:
public static class RadControlExtensions
{
public static RadDockZoneSetting GetSettings(this RadDockZone dockZone)
{
RadDockZoneSetting radDockZoneSetting = new RadDockZoneSetting(dockZone.UniqueName, dockZone.ID, dockZone.Skin, dockZone.MinHeight,
dockZone.HighlightedCssClass, dockZone.BorderWidth, dockZone.Parent.ID);
return radDockZoneSetting;
}
public static RadTabSetting GetSettings(this RadTab tab, int index)
{
RadTabSetting radTabSetting = new RadTabSetting(tab.Text, tab.Value, index);
return radTabSetting;
}
//Continued
}
The control that is being recreated is guaranteed to have this extension method (would be nice to enforce this, though.)
I'm now at:
public static T Recreate<T>() where T : new()
{
T _control = new T();
//Not right -- you can't cast a control to an extension method, obviously, but
//this captures the essence of what I would like to accomplish.
(_control as RadControlExtension).SetSettings();
Logger.DebugFormat("Recreated control {0}", (_control as Control).ID);
return _control;
}
What should I be looking into to support this, if possible?
If you know that every _control that gets passed will be a RadDockZone (or derived from RadDockZone) just do this:
T _control = new T();
(RadDockZone)_control.SetSettings();
Logger.DebugFormat("Recreated control ... //rest of code here
If it's not always going to be a RadDockZone, you'll need to do some type checking to get the right type to call the extension method. I'm presuming, there, that you have a .SetSettings() extension method on all the possible Types that could be passed to your Recreate method.
You need to cast your T to something that is supported by your extension method.
(_control as RadDockZone).GetSettings
Extension methods operate on a type they are not a type in the traditional sense. The 'SomeFn(string this)' makes your extension work on things that are strings which would be strings and anything derived from them.
If I understand correctly what you are trying to do, just put a constraint on T:
public static T Recreate<T>() where T : RadControl, new() {
// etc.
}
You might have to use double dispatch and define
public static RadControl GetSettings(this RadControl control) {
}
which will invoke the appropriate GetSettings method.
No, Jason's answer is the cleaner way to go. The accepted solution killed the type safety and made use of generics pointless. You could switch to generic-less design (having a RadControlFactory) and had the job done.