I have a method like the following:
public IEnumerable<T> GetControls<T>()
: where T : ControlBase
{
// removed.
}
I then created a class:
public class HandleBase<TOwner> : ControlBase
: TOwner
{
// Removed
}
I'd like to be able to call
GetControls<HandleBase<this.GetType()>>;
where it would use the type of THIS class to pass to the HandleBase. This would in essentially get all HandleBase that have an owner of THIS type.
How can I achieve this?
EDIT:
I'm using .NET 2.0 so solutions greater than 2.0 will not work.
The idea is to have ControlBase have a collection of other ControlBase for "children". Then they can be queried based on their type with GetControls<T>(). This would allow me to, for example, get all HandleBase for a Shape. Then I can take all of these and set Visible=false or do something else with them. Thus I can manipulate children of a specific type for a collection.
HandleBase<TOwner> requires the TOwner since it has a reference to the "owning type". So you can only add anything that extends HandleBase to a Shape. Make sense?
Thanks for all the help!
You can do this either by specifying a type at compile-time or by using reflection.
You can do it with reflection like this:
typeof(SomeClass).GetMethod("GetControls")
.MakeGenericMethod(typeof(HandleBase<>).MakeGenericType(GetType()))
.Invoke(someObject, null);
Note that it would return an object; you would not be able to cast it to IEnumerable<T> (Unless you know what T is at compile-time, in which case there's no point). You would be able to cast it to IEnumerable.
However, this is a bad idea.
There is probably a better solution for you; please provide more detail.
You can't. Generics is a compile-time feature. You would need to include the type as a non-generic parameter to the method, and pass it in there.
Note that type parameters are not variables. Therefore, you cannot use a variable in place of a type parameter.
You could, however, do this through reflection, or by using a special construct which is pretty limited but may solve your case:
public class MyClass<TSelf> where TSelf: MyClass<TSelf> {
public IEnumerable<T> GetControls<T>() where T: ControlBase {
// removed.
}
public void MyCall() {
GetControls<HandleBase<TSelf>>();
}
}
public class MyConcreteClass: MyClass<MyConcreteClass> {
}
Probably there is no way to do what you ask for. Extending your example:
X x = GetControls<HandleBase<this.GetType()>>;
What should the type X be here? However from other background information it seems that you need to get list of all controls of given type. You could do this for example in such way:
public IEnumerable<ControlBase> GetControls(Type type) {
//your logic here
}
Depending on your other usages and goals you might also want to return non-generic IEnumerable.
Since GetControls() returns an enumeration, you might find a way to filter the resulting enumeration with .OfType<T>, something like
List<T2> list = controlList.GetControls<T>().OfType<T2>().ToList();
You would need a generic constraint somehwere along the lines of
where T2 : T
This is specific to my implementation of this but I was able to solve this by creating a non-generic HandleBase first and then a generic HandleBase<TOwner> since the only place TOwner was being used was the property Owner.
Then when I can call GetControls<HandleBase> and get all HandleBase regardless of the Owner.
Thanks all for answers!
Related
I've written a method with the signature:
private List<ClientItem> ConvertToClientItems(BaseCollection<object> serverItems)
I'm trying to call it in the following manner:
ConvertToClientItems(approvedSellers);
where approvedSellers is of type BaseCollection<Seller> - with Seller being a class that I don't have control over.
Shouldn't this be possible? Visual Studio is throwing an error at me saying that it cannot cast BaseCollection<seller> to BaseCollection<object>.
Well, imagine code that looks like this:
private List<ClientItem> ConvertToClientItems(BaseCollection<object> serverItems) {
serverItems.Add(new Buyer());
}
This should compile, since a Buyer is an object.
However, if you pass a BaseCollection<Seller>, you just tried to add a buyer to a list of sellers.
Thus, the statement
BaseCollection<Seller> is a subtype of BaseCollection<object>
only holds if BaseCollection ensures that the generic type T is only used in output positions. The Add example above would use T in an input position.
To solve this, you have the following options:
Make BaseCollection "covariant" by adding the out keyword, which would require removing any Add methods. This, however, might make your collection kind of useless.
Pass a covariant interface to the method. If you only need to read serverItems, pass an IEnumerable, which is already covariant (and you mention in the comments that BaseCollection already implements IEnumerable):
private List<ClientItem> ConvertToClientItems(IEnumerable<object> serverItems) {
// You can only read serverItems here, so we are fine.
}
make the method itself generic
private List<ClientItem> ConvertToClientItems<T>(BaseCollection<T> serverItems) {
// This also prevents the evil `Add` call, since you'd need to create
// an object of the correct type T first.
}
In BaseCollection, you have to make T covariant by using the "out" keyword.
More information http://msdn.microsoft.com/en-us/library/dd233059.aspx.
(IEnumerable works because it is covariant.)
public interface BaseCollection<out T>
So my real method is a lot different but I come down to this. It seems I don't fully understand how to handle the generic <T> type when I'm working with generic methods. My understanding is that we use generic methods when we want the same logic to work for different types, but we want the freedom to determine the exact type at run time. So it seems pretty natural to me that when I have a method like this :
internal static void ChangeCode<T>(Entity entity) where T : Entity
{
T tempEntity;
if (entity.GetType() == typeof(SomeMoreSpecificEntity))
{
tempEntity = new SomeMoreSpecificEntity();
}
}
However if I try something like this I get an error Can not convert type T to SomeMoreSpecificEntity.
So where am I wrong. Isn't the idea to be able to do exactly this - declare a common type in compile time and cast to more specific type in run time?
You can't do that. Check following situation:
You have another class named SomeMoreSpecificEntity2 which is declared:
class SomeMoreSpecificEntity2 : Entity
{
}
You call your method ChangeCode<SomeMoreSpecificEntity2>, so T is SomeMoreSpecificEntity2, so tempEntity is SomeMoreSpecificEntity2 as well, but you're trying to assign SomeMoreSpecificEntity to it. That can't work.
You can try changing it to :
internal static void ChangeCode<T>(Entity entity) where T : Entity
{
Entity tempEntity;
if (entity.GetType() == typeof(SomeMoreSpecificEntity))
{
tempEntity = new SomeMoreSpecificEntity();
}
}
It compiles.
No, the code you're trying to write is broken. For example, suppose I called:
ChangeCode<BananaEntity>(new SomeMoreSpecificEntity());
That would try to assign a reference of type SomeMoreSpecificEntity to a variable of type T, where T is BananaEntity.
It's not clear what you're trying to achieve, but that's why your current code won't compile. Given that you're not actually using T other than for a purpose for which it won't work your current code could be changed to make it a non-generic method, and just declare tempEntity as type Entity. Of course, that might not work for what you really want to do, but as you've only provided the non-working code, that's hard to determine :(
Three points about this line:
if (entity.GetType() == typeof(SomeMoreSpecificEntity))
Did you actually mean entity to be of type T rather than type Entity? Currently it can be any entity
Did you really want to check the exact type? Normally you'd use is instead of calling GetType and comparing it directly with a type
Normally comparing types like this is a sign that you should consider a redesign. It's definitely not generic at this point, as it only copes with types that are hard-coded in it.
tempEntity = (T)(object)new SomeMoreSpecificEntity();
T can only cast with object
I suspect the answer is no, but I want to know if it is possible to do something like this:
public class MyGenericClass<TSomeClass> {
public void MyGenericMethod<TSomeInterface>()
// This doesn't compile.
where TSomeClass : TSomeInterface
{
//...
}
}
What I mean to indicate in the above (non-working) example is to constrain TSomeInterface such that it can be any base class, implemented interface, or (if you really want to get fancy) implicit conversion of MyGenericClass.
NOTE:
I suspect that the reason why this was never implemented in C# is that generic constraints are not really meant to be code contracts, which is how I am trying to use them here. I really don't care what type TSomeInterface is, so long as it is implemented by TSomeClass.
So far, I have hacked this together:
public class MyGenericClass<TSomeClass> {
public void MyGenericMethod<TIntermediateType, TSomeInterface>()
where TIntermediateType : TSomeClass, TSomeInterface
{
//...
}
}
This more or less enforces the constraint that I want (that TSomeClass must inherit from, or in the case of an interface, implement, TSomeInterface), but calling it is very clumsy, because I have to specify TIntermediateType (even though I really want it to evaluate against TSomeClass):
var myGenericInstance = new MyGenericClass<TSomeClass>();
myGenericInstance.MyGenericMethod(TSomeClass, TSomeInterface);
Additionally, the above hack is broken because a caller could in theory specify a subclass of TSomeClass as the first type parameter, where only the subclass implements TSomeInterface.
The reason that I want to do this is that I am writing a fluent factory pattern for a WCF service, and I would like to prevent the caller (at compile time) from trying to create an endpoint with a contract that the service class doesn't implement. I can obviously check this at runtime (WCF in fact does this for me), but I am a big fan of compile-time checking.
Is there a better/more elegant way to achieve what I am after here?
The way I was able to wrap my head around the reason why this doesn't compile is the following:
Consider this program compiles:
class Program {
class Class1 { }
class Class2 { }
public class MyGenericClass<TSomeClass> {
public void MyGenericMethod<TSomeInterface>() where TSomeClass : TSomeInterface {
}
}
static void Main(string[] args) {
var inst = new MyGenericClass<Class1>();
}
}
Everything is good. The compiler is happy. Now consider I change the Main method:
static void Main(string[] args) {
var inst = new MyGenericClass<Class1>();
inst.MyGenericMethod<Class2>();
}
The compiler will complain that Class1 does not implement Class2. But which line is wrong? The constraint is on the call to MyGenericMethod, but the offending line of code is the creation of MyGenericClass.
In other words, which one gets the red squiggly line?
As discussed in this linked question, you can't use a type parameter that isn't from the current declaration, on the left side of a where clause.
So as suggested by w0lf in that other question, what you can do is provide both types in your interface (rather than method) declaration:
public class MyGenericClass<TSomeClass, TSomeInterface> {
where TSomeClass : TSomeInterface
public void MyGenericMethod() // not so generic anymore :(
{
//...
}
}
That, however, greatly limits your MyGenericMethod and forces your class to declare before-hand what base interface you with to allow.
So another option is to use a static method with more type parameters:
public class MyGenericClass<TSomeClass> {
public static void MyGenericMethod<TSomeClass, TSomeInterface>
(MyGenericClass<TSomeClass> that)
where TSomeClass : TSomeInterface
{
// use "that" instead of this
}
}
Possibly you could make it an extension method to make it appear to the user like an actual method.
Neither of these is exactly what you wanted, but probably better than the intermediate type solution.
As for the reason for why not?, my guess is that it would complicate the compiler without adding enough value. Here's a discussion by Angelika Langer of the same subject but about Java. Although there are significant differences between C# and Java, I think her conclusion might apply here as well:
The bottom line is that the usefulness of lower bounds on type
parameters is somewhat debatable. They would be confusing and perhaps
even misleading when used as type parameters of a generic class. On
the other hand, generic methods would occasionally profit from a type
parameter with a lower bound. For methods, a work-around for the
lack of a lower bound type parameter can often be found. Such a
work-around typically involves a static generic method or a lower
bound wildcard.
She also gives a nice use case, see the link above.
An extension method provides the best solution, though it doesn't totally solve all your concerns.
public class MyGenericClass<TSomeClass>
{
}
public static class MyGenericClassExtensions
{
public static void MyGenericMethod<TSomeClass, TSomeInterface>(this MyGenericClass<TSomeClass> self)
where TSomeClass : TSomeInterface
{
//...
}
}
It is still necessary to specify both types when calling MyGenericMethod, but it prevents the caller from specifying an incorrect type for TSomeClass as is possible with the approach you came up with. With this approach, the method can be called like so:
var myGenericInstance = new MyGenericClass<TSomeClass>();
myGenericInstance.MyGenericMethod<TSomeClass, TSomeInterface>();
It will be a compile error if the type parameter MyGenericClass is declared with does not match the first type parameter to MyGenericMethod.
Since the first type parameter can be inferred by the this argument, it is often possible for the compiler to infer both type parameters if their additional parameters to the method.
All, I have an application that needs to attach and detach multiple SQL databases regularly. I want to create a class that holds all of these databases as a collection that can be iterated over. To do this I am inheriting from ICollection, but there is some thinkg I am not understanding:
class SqlDataBases : ICollection<SqlDb>
{
private List<SqlDb> dbColl;
public SqlDataBases()
{
dbColl = new List<SqlDb>();
}
// Add an index to the collection.
public SqlDb this[int _nIndex]
{
get { return (SqlDb)dbColl[_nIndex]; }
set { dbColl[_nIndex] = value; }
}
// et al.
}
public class DbEnumerator : IEnumerator<SqlDb>
{
// ...
}
class SqlDb
{
private string strMdfFullPath;
private string strLdfFullPath;
private bool bIsAttached;
public SqlDb(string _strMdfFullPath, string _strLdfFullPath, bool _bIsAttached)
{
this.strMdfFullPath = _strMdfFullPath;
this.strLdfFullPath = _strLdfFullPath;
this.bIsAttached = _bIsAttached;
}
}
My question is "why inherit from ICollection at all, when you have to add methods such as 'Add', 'Contains' etc. yourself? Or do you have to do this yourself as suggested in MSDN? I have been reading "C# in a Nutshell" and this question is something that stands out unaddressed in this great book.
I apologise, I know I am missing something here...
My question is "why inherit from ICollection at all, when you have to add methods such as 'Add', 'Contains' etc. yourself?
ICollection<T> is an interface - it just specifies the members that you have to implement. If you want to derive from something which already has an implementation, look at Collection<T>. You would implement the interface yourself if you wanted to create your own collection data structure with its own special characteristics - I doubt that you want to do that.
To be honest, it's not clear why you want your own class here at all - why not just use List<SqlDb> in the client code directly?
Have you thought about using List<SqlDb> directly?
It's not obvious to me what you hope to gain by the SqlDataBases class.
If you can't use List<SqlDb> directly, think about inheriting from List<SqlDb> rather than ICollection<SqlDb>.
Interfaces are only skeletons. They aren't containing any logic, they are containing only the signatures of all method, property etc.
Interfaces
The reason to inherit from ICollection<> is to create your own custom collection type. Then, anywhere a method has an input variable of ICollection<>, because you inherited from ICollection<>, your new custom collection type can be passed in.
In your case, you could simply use List<> until you find a need to create a custom collection.
Answering "why inherit from ICollection at all, when you have to add methods such as 'Add'":
you don't need to inherit ICollection if you don't need/want to have Add/Next etc.
I have a method
private object SetGrid(IGrid grid)
{
grid.PagerHelper.SetPage(1, 10);
grid.SortHelper.SetSort(SortOperator.Ascending);
grid.PagerHelper.RecordsPerPage = 10;
return grid;
}
which returns an object of type object.
Then I cast the object back to the previous type.
var projectModel = new ProjectModel();
projektyModel = (ProjectModel)SetGrid(projectModel);
The gain of this is, the method SetGrid can be reused across the app.
Is this a common practice or should I avoid doing this ?
You could use a generic method instead, and constrain the type argument to your IGrid interface:
private T SetGrid<T>(T grid) where T : IGrid
{
grid.PagerHelper.SetPage(1, 10);
grid.SortHelper.SetSort(SortOperator.Ascending);
grid.PagerHelper.RecordsPerPage = 10;
return grid;
}
You should still be able to call the method in exactly the same way, just without the cast. Type inferencing should be capable of automagically figuring out the required generic type argument for you:
var projectModel = new ProjectModel();
projektyModel = SetGrid(projectModel);
EDIT...
As other answers have mentioned, if your IGrid objects are reference types then you don't actually need to return anything at all from your method. If you pass a reference type then your method will update the original object, not a copy of it:
var projectModel = new ProjectModel(); // assume that ProjectModel is a ref type
projektyModel = SetGrid(projectModel);
bool sameObject = object.ReferenceEquals(projectModel, projektyModel); // true
Since you are passing in an object of a class that implements IGrid you could just as well change the return type to IGrid.
Also, since it's a reference type you don't even need to return the grid again. You could just as well use this:
var projectModel = new ProjectModel();
SetGrid(projectModel);
This is better accomplished with generics. You can use a constraint on the generic typeparam to preserve your type safety!
private T SetGrid<T>(T grid) where T : IGrid
{
grid.PagerHelper.SetPage(1, 10);
grid.SortHelper.SetSort(SortOperator.Ascending);
grid.PagerHelper.RecordsPerPage = 10;
return grid;
}
and then
var projectModel = new ProjectModel();
projectModel = SetGrid(projectModel);
Here, the generic typeparam "T" is actually inferred by the compiler by the way you call the method.
It's worth noting that in the particular use-case you've demonstrated, returning grid is probably unnecessary, as your original variable reference will be appropriately modified after the method call.
In the case you illustrate above there is no need to return grid. The IGrid instance is passed by reference, so your projectModel reference will be updated with the changes you've made in the SetGrid method.
If you still want to return the argument, at least return IGrid, since it is already known that the argument is an IGrid.
In general, provide as much type information as you can when programming in a statically typed language/manner.
"Is this a common practice or should I avoid doing this ?"
This is not common practice. You should avoid doing this.
Functions that only modify the parameter passed in should not have return types. If causes a bit of confusion. In the current C# you could make the modifying function an extention method for better read-ability.
It causes an unnecisary cast of the return type. It's a performance decrease, which may not be noticable... but its still needless since you are casting from an interface, return that interface even if the object is different from the parameter passed in.
Returning object is confusing to users of the function. Lets say the function created a copy and returned a copy... you would still want to return the interface passed in so that people using the function know "hey i'm getting an IGrid back." instead of having to figure out what type is being returned on thier own. The less you make your team mates think about stuff like this the better, for you and them.
This is a very weird example because SetGrid doesn't seem to do a lot of things other than setting some defaults. You are also letting the code perform manipulation on the object that could very well do that by itself. Meaning IGrid and ProjectModel could be refactored to this:
public interface IGrid {
// ...
public void setDefaults();
// ...
}
public class ProjectModel : IGrid {
// ...
public void setDefaults() {
PagerHelper.SetPage(1, 10);
SortHelper.SetSort(SortOperator.Ascending);
PagerHelper.RecordsPerPage = 10;
}
// ...
}
Using this refactoring you only need perform the same with this:
myProjectModel.setDefaults();
You could also create an abstract base class that implements IGrid that implements the setDefaults() method and let ProjectModel extend the abstract class.
what about the SOLID principles ? Concretely the Single Responsibility Principle. The class is in the first place something like a DTO. – user137348
I'm exercising the Interface Segregation Principle out of the SOLID principles here, to hide the implementation from the client of the class. I.e. so the client doesn't have to access the internals of the class it is using or else it is a violation of Principle of Least Knowledge.
Single Responsibility Principle (SRP) only tells that a class should only have one reason to change which is a very vague restriction since a change can be as narrow and broad as you want it to be.
I believe it is okay to put some configuration logic in a parameter class if it is small enough. Otherwise I'd put it all in a factory class. The reason I suggest this solution is because IGrid seems to have reference to PagerHelper and SortHelper that seem to be mutators for IGrid.
So I find it odd that you mention the class being a DTO. A DTO from a purist sense shouldn't have logic in it other than accessors (i.e. getter methods) which makes it strange that ProjectModel itself has references to PagerHelper and SortHelper which I assume can mutate it (i.e. they're setters). If you really want SRP the "helpers" should be in a factory class that creates the IGrid/ProjectModel instance.
Your grid is an IGrid, why not return IGrid?