|
Ok, but in non-generic syntax this works:
private void Button_Click(object sender, RoutedEventArgs e)
{
Calc(1);
}
private void Calc(object val)
{
}
but in generic syntax it doesn't?
____________________________________________________________
Be brave little warrior, be VERY brave
|
|
|
|
|
"Shouldn't"; there's a difference between simple types (anything that's a value) and classes, that's why there's a "where T:class" constraint
I are Troll
|
|
|
|
|
I know that, and object allows me to pass either and respond accordingly inside the method to which I passed the parameter
____________________________________________________________
Be brave little warrior, be VERY brave
|
|
|
|
|
..because you can check what type of object that it is. That's what VS does at compile-time, and since an integer isn't an object it gives an error. It could be wrapped in an object, that's true - but if that's what should be done, then it has to be explicit. Remember that you can't inherit from an integer, so it does make sense to differentiate between the parameter-behaviour and the generics' behaviour
I are Troll
|
|
|
|
|
In .net, everything is an object.
|
|
|
|
|
That's one of those generalizations that I loathe. Yes, structs are objects too.
..but that doesn't make 'em interchangeable
I are Troll
|
|
|
|
|
Eddy Vluggen wrote: but that doesn't make 'em interchangeable
Yes it does, assuming the container being used to intercahnge them types the variable as object.
|
|
|
|
|
J4amieC wrote: Yes it does, assuming the container being used to intercahnge them types the variable as object.
The keyword here is "assuming", and your assumption is a leaky abstraction
Reference-types are objects, value-types can be boxed in an reference-type. And no, a namespace isn't an object, it's not even a type.
Once you state that everything is an object, people will assume that anything can be used as a base to derive from (since OO is partly about inheriting from existing objects).
I are Troll
|
|
|
|
|
Eddy Vluggen wrote: Once you state that everything is an object, people will assume that anything can be used as a base to derive from
Any non-sealed Type can be used as a base to derive from. What's your point?
|
|
|
|
|
J4amieC wrote: Any non-sealed Type can be used as a base to derive from.
You can circumvent the impossibility of inheriting a structure by pointing out that it's a sealed class - but that doesn't change the validity of my statement. I took the example of a namespace to prevent the hairsplitting discussion that structs are merely mutilated classes under the hood
J4amieC wrote: What's your point?
That the text "everything is an object" is incorrect. I stated that literally, didn't I?
I are Troll
|
|
|
|
|
(Whoops, sorry to have started that. )
|
|
|
|
|
The reason you can't do it is fairly simple. Action<T> is generic - fair enough, and you want it to be Action<object> - ok? Simplistically you would think this would work because no matter what type T was, it would ultimately be convertable to object, as everything derives from object.
Suppose though, that type T was a string, and you wanted to use Action<int> - all of a sudden, there's a conversion that is not implicitly possible - in other words, you would have to perform an explicit cast. The cast into object would have to be a special case in the compiler, so they chose not to do this - instead, like for like typing is the only way to achieve this.
|
|
|
|
|
Thanks for the reply Pete, just not sure I fully understand your explanation.
What you are saying that (assuming this was allowed) this wouldn't be a problem:
Action<object> act = null;
act = new Action<int>();
but the problem would come in if I tried:
act("a");
If that's what you are saying then I'm a bit disappointed in MS because type conversion from object has always posed this challenge (I recon this is why generics was brought in) and yes its fair to expect me to pass the right value in or get a runtime error...
____________________________________________________________
Be brave little warrior, be VERY brave
|
|
|
|
|
That's exactly what I'm saying. The thing is though, generics were brought in for things like type safety and to prevent aid the developer move away from boxing/unboxing. By having object as the generic type, you've just gone back to having a boxing/unboxing issue - and you're no better off than just passing Action across rather than the generic Action.
|
|
|
|
|
I understand that I should avoid boxing & un-boxing (and I do want to, and I do it everywhere), in this case it's not an option. Bit of a complex scenario I'll have to explain (and the code is part of a 5 000 file solution), but I'm quite irritated that this is disallowed, I thought polymorphism / covariance / contravariance is exactly about this...
____________________________________________________________
Be brave little warrior, be VERY brave
|
|
|
|
|
It is, for objects - aka reference-types, not for value-types. C# is really strict on the difference.
The posted alternative with the interface does look like it (could) solve your problem. Alternatively, you could decide only to pass objects, and to wrap your ints in a MyInt class.
I are Troll
|
|
|
|
|
It's a design issue and it makes sense when you think about it. If you want to use a collection of type object, then use ArrayList. The generic List is a strongly typed version of ArrayList, so if strong typing is not required, use ArrayList.
"You get that on the big jobs."
|
|
|
|
|
Why not just to the following, from what I could see would give youthe exact same result, with the benefit of actually compiling!
public interface IBase<T>
{
Func<T> OnComplete { get; set; }
}
public class Base : IBase<object>
{
public Base(Func<object> onComplete)
{
OnComplete = onComplete;
}
public Func<object> OnComplete { get; set; }
}
public class GenericBase<T> : IBase<T>
{
public GenericBase(Func<T> onComplete)
{
OnComplete = onComplete;
}
public Func<T> OnComplete { get; set; }
}
|
|
|
|
|
Generic inheritance is a bit complicated. Here's the reason that you can't cast 'down' the generic type parameter inheritance tree.
Imagine this test class:
class BadMistake {
void CompleteHandler(Dictionary<string,int> complexParameter){
}
GenericBase<Dictionary<string,int>> instance;
public void CauseDeath(){
instance = new GenericBase<Dictionary<string,int>>(CompleteHandler);
((Base)instance).OnComplete(16);
}
}
Now, CompleteHandler is expecting to be passed a Dictionary, and you can't compile something which would cause that not to be the case. But using the base class, you can pass an int (or anything else) to it.
Method parameter compatibility for generics works backwards. This example will compile if the type parameter in the base is a subclass of T, for example try:
public class Base
{
public Func<T> OnComplete {get;set;} where T:Panel
public Base(Func<T> onComplete) where T:Panel
{
OnComplete = onComplete;
}
}
public class GenericBase<T> : Base
{
public GenericBase(Func<T> onComplete) where T:UserControl : base(onComplete)
{
OnComplete = onComplete;
}
}
(if I got the syntax on the constructor there right).
Also, there isn't really a reason to make a non generic base type and inherit from it in this way. You can just use a GenericBase<object> if you want one that can deal with anything.
|
|
|
|
|
Because it just can't. If asked questions such as this I like to mutter something about Covariance and Contravariance and wonder off. Usually works in the office environment anyway.
Regards,
Rob Philpott.
|
|
|
|
|
Rob Philpott wrote: Covariance and Contravariance
I thought those were added in .net 4.
|
|
|
|
|
|
Hi,
I'm growing grey early here... I severly need HELP.
When using Visual Studio 2010 (express?)...
...if you click File => "New Project", where do you specify the directory on disk?
I've been creating all sorts of project in random user directories and IT'S DRIVING ME CRAZY! Why can't I specify the directory where VS2010 creates the solution?!? Why can't I start a project in D:\projects?
This is one of the things which drives me away from .net, even tho it's the platform of choice here...
A good programmer is someone who always looks both ways before crossing a one-way street. (Doug Linder)
|
|
|
|
|
Helfdane wrote: I'm growing grey early here... I severly need HELP.
Really?
Visual Studio (all versions) behaves pretty much the same as most other Windows applications (e.g. MS Word): you can create a new something in memory, and it will ask you for a path if and when that becomes unavoidable, e.g. when telling the app to save, to close, to quit, to open up another thing that causes the current one to close first, etc. Then a dialog will pop up and you will be in charge of file locations.
I tend to save early on, to get that out of the way; but there is no need to do so.
Luc Pattyn [Forum Guidelines] [My Articles] Nil Volentibus Arduum
Please use <PRE> tags for code snippets, they preserve indentation, improve readability, and make me actually look at the code.
|
|
|
|
|
You're not correct regarding Visual Studio 2010 Express (10.0.30319.1 RTMel). There is only a project template (installer installed only the C# template) which you can choose and the only boxes where you can type something is the solution name and the search box.
A good programmer is someone who always looks both ways before crossing a one-way street. (Doug Linder)
|
|
|
|