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>
Related
Does anyone have a better way to do the following:
typeof(Service).GetMethod("UpdateData")
.MakeGenericMethod(dataType)
.Invoke(_myService, new object[]{ editData, metaData });
I'd love to do something like:
_myService.UpdateData<dataType>(editData, metaData);
But the <> accessor for generics will not take Type objects. I'm looking for a helper, utility, accessor, or something to make those generic method calls with reflection less cumbersome or at least centralized.
More Specific Example
public class UserService : IUserService
{
async Task<User> UpdateUser<T>(User user, JsonPatchDocument<T> patch){ //do code }
}
Type dtoType = MagicService.getDynamicDtoType();
Type patchType = typeof(JsonPatchDocument<>).MakeGenericType(dtoType);
dynamic patchDoc = _mapper.Map(patch, typeof(JsonPatchDocument<User>), patchType);
User updateUser = await (Task<User>)typeof(UserService).GetMethod("UpdateUser").MakeGenericMethod(dtoType).Invoke(_userService, new object[]{user, patchDoc})
This actually ends up with two issues. One, the dynamic patchDoc isn't the right type to be used in UpdateUser, which I have a separate question in Stackoverflow about (but you can use duck typing here), and the messy calling of that generic method call with reflection. I'm trying to solve both, but for this question I want to clean up the call. If you have ideas on the other piece, which is really a separate issue:
Declaring a type in C# with a Type instance
This answer does not use reflection, but may make your code easier to work with in some circumstances.
We could have a class like this:
public class MyService
{
public void UpdateData<T>(Something data, Something otherData)
{
// do stuff
}
}
Later we find that we have to call it using a Type variable instead of a generic argument, which could mean using reflection. Sometimes it's easier to add a non-generic overload to the original class, and call it from the generic method:
public class MyService
{
public void UpdateData(Type dataType, Something data, Something otherData)
{
// do stuff
}
public void UpdateData<T>(Something data, Something otherData)
{
UpdateData(typeof(T), data, otherData);
}
}
We lose the ability to easily impose constraints on the Type argument like we could with the generic method. We can add validation if we need it.
That gets you as close as possible to the code you're trying to write:
_myService.UpdateData(dataType, editData, metaData);
That's assuming that you find yourself still needing the generic methods at all. If you add non-generic overloads and discover that you're not calling the generic ones anymore, you can just delete them.
A significant benefit of this over reflection is that you can identify where your code is called. A method that's only called using reflection will appear unused.
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 have created a class, MonitoredCollection<T>, that basically encapsulates/mimics List but allows me to fire events on certain calls.
Now however, whereever there is a parameter that takes a MonitoredCollection, where T is an Interface, I can no longer pass a MonitoredCollection<T> where T is a class that implements that interface, like I could with a List.
I always thought that interfaces were a language 'feature' and therefore I don't need to implement anything more to support this, so what have I missed?
EDIT: Sorry, I made a mistake in that question, as João correctly pointed out List never worked in this instance so the question is as it stands without that!
Suppose you have a MonitoredCollection<SomeObject> instance, and you want to treat it as a MonitoredCollection<ISomeInterface> instance where SomeObject does in fact implement ISomeInterface. This does not create any problems for retrieving items from the collection, since object of type SomeObject can be converted to the interface type ISomeInterface.
However, for all the methods on your collection which modify the collection, such as those that assign a new value to an index, or insert a new item into the collection, this cast has created a whole suite of issues. I'd assume your MonitoredCollection<SomeObject> instance would have a method such as Add(SomeObject obj), which would insert a new object into the collection. After the cast, the signature on this method would be Add(ISomeInterface obj). This seems to make sense, but not all ISomeInterface objects are NECESSARILY SomeObject instances.
Because the casted object will allow operations on the collection that the original object wouldn't allow, the runtime won't allow this cast. C# 4.0 introduced covariance and contravariance to explicitly state what is valid for casts of this type, you can look into them for trying to solve this issue. However, you're really only going to have luck with a read only version of your collection (think List<T>.AsReadOnly()).
Unfortunately, you can't do that with a list either. The compiler still cannot convert the types. You need to use a generic method. See code below:
class Test
{
void DoTest()
{
MonitoredList<IInterface> mlist1 = new MonitoredList<Inherited>(); //Error
MonitoredList<Inherited> mlist2 = new MonitoredList<Inherited>();
DoSomething1(mlist2); //Error converting MonitoredList<Inherited> to MonitoredList<IInterface>
MonitoredList<IInterface> list1 = new MonitoredList<Inherited>(); //Error
MonitoredList<Inherited> list2 = new MonitoredList<Inherited>();
DoSomething2(list2); //Error converting List<Inherited> to List<IInterface>
DoSomething3<Inherited>(mlist2); //Works fine
DoSomething3(mlist2); //<Inherited> is redundant
}
void DoSomething1(List<IInterface> list)
{ }
void DoSomething2(MonitoredList<IInterface> list)
{ }
//Generic method
void DoSomething3<T>(MonitoredList<T> list) where T : IInterface
{ }
}
interface IInterface { }
class Inherited : IInterface { }
class MonitoredList<T> { }
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!
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?