Generic Delegate Meltdown From Constraint

  • Thread starter Thread starter NaughtDivisor
  • Start date Start date
NaughtDivisor said:
OK. One simplified question, one question whose solution is alluding
me.

1.) How does one pass, as an argument, a constrained generic class to
a method in a non-generic class?

The constraint part is irrelevant. You pass it as normal, but it will
depend on the method. (In fact, you never pass a generic class - you
pass an instance, or rather a reference to an instance.)

Could you give an example of what you mean? Bear in mind that a method
in a non-generic class can still be a generic method.

If you can give an example you've found which works *without* a
constraint, but you're having trouble *with* the constraint, I'm sure
we can help you.
2.) How does one pass, as an argument, a constrained generic class to
a delegate field in a non-generic class?

You don't "pass" anything to a field. You can assign values, although
that should be done within the class.

Again, what is your actual objective? Why do you still need (or think
you need) it to be generic in the non-generic class?
 
Thank you Pete, you have finally found the root of my angst:


ERROR:

The type 'T' cannot be used as type parameter 'T' in the generic type
or method 'CODE_TESTER.MyClass<T>'. There is no boxing conversion or
type parameter conversion from 'T' to 'CODE_TESTER.MyConstraint'.

namespace CODE_TESTER
{

public class MyClass<T> where T : MyConstraint
{
}

public class MyConstraint
{
}

delegate void MyDelegate<T>(MyClass<T> arg) where T :
MyConstraint;


class MyOtherClass
{
MyDelegate<MyConstraint> mydelegate1 = MyMethod;
MyDelegate<MyConstraint> mydelegate2 = MyMethod<MyConstraint>;


// non-generic method in a non-generic class
// taking an instance of the generic class


void MyMethod(MyClass<MyConstraint> arg)
{
}


// generic method in a non-generic class
// taking an instance of the generic class


void MyMethod<T>(MyClass<T> arg)
{
}


void MyCaller()
{
mydelegate1(new MyClass<MyConstraint>());


mydelegate2(new MyClass<MyConstraint>());
}
}


}
 
Thank you Pete, you have finally found the root of my angst:


ERROR:

The type 'T' cannot be used as type parameter 'T' in the generic type
or method 'CODE_TESTER.MyClass<T>'. There is no boxing conversion or
type parameter conversion from 'T' to 'CODE_TESTER.MyConstraint'.

And where did you get that error?

Looking at the code I posted, I suspect it was on the declaration of the
generic method MyMethod<T>, where I should have specified a constraint.
That is, instead of:

void MyMethod<T>(MyClass<T> arg)
{
}

I should have written:

void MyMethod<T>(MyClass<T> arg) where T : MyConstraint
{
}

That way the type parameter for MyMethod<T> can be legally used as the
type parameter for MyClass<T> as well.
If that doesn't address your compile error, you need to be more specific.

I'm not sure what you mean by "you have finally found the root of my
angst". It would have been better to compile the example I posted to
double-check my work, but I don't see how fixing that addresses the
questions you asked. It might address the question you _wanted_ to ask,
but it doesn't have anything to do with the questions you did ask.

Pete
 
NaughtDivisor said:
Thank you Pete, you have finally found the root of my angst:

ERROR:

The type 'T' cannot be used as type parameter 'T' in the generic type
or method 'CODE_TESTER.MyClass<T>'. There is no boxing conversion or
type parameter conversion from 'T' to 'CODE_TESTER.MyConstraint'.

Right - so add the constraint to T in the MyMethod<T> method as well:

void MyMethod<T>(MyClass<T> arg) where T : MyConstraint
{
}

That removes that issue, but you get some other errors, which are
nothing to do with generics - basically you can't specify an instance
field initializer which uses the "this" pointer. You could initialize
mydelegate1 or mydelegate2 inside a constructor, or you can make the
methods called MyMethod static.

For testing purposes I made MyMethod (both versions) static.

The code then compiled without error.
 
So thank you all for bearing with me.

My next question is how do you send in two arguments that are
differently constrained?

No need to answer. Event args have become my friend.
 
[...]
That removes that issue, but you get some other errors, which are
nothing to do with generics - basically you can't specify an instance
field initializer which uses the "this" pointer. You could initialize
mydelegate1 or mydelegate2 inside a constructor, or you can make the
methods called MyMethod static.

For testing purposes I made MyMethod (both versions) static.

Thanks. :) I guess I really should have compiled that example...that's
an embarassing number of things I overlooked.

Sorry for any confusion.
The code then compiled without error.

Yay! :)

Pete
 
So thank you all for bearing with me.

My next question is how do you send in two arguments that are
differently constrained?

No need to answer. Event args have become my friend.

I don't know what you mean by "event args" in this context, or how they
answer your (apparently) rhetorical question. But I'm glad you know the
answer.

If you should change your mind, please feel free to ask it again.

Pete
 
On closing, thank you very much all for being helpful.

Yes I do feel like an idiot. As I thought the solution is quite
simple I just got panicked and ran off in the wrong direction.

I had initially tried this:

void MyMethod<T>(MyClass<T> arg)
{
}

way back before posting and in my panic read the error message

"The type 'T' cannot be used as type parameter 'T' in the generic
type
or method 'CODE_TESTER.MyClass<T>'. There is no boxing conversion or
type parameter conversion from 'T' to 'CODE_TESTER.MyConstraint'"

As precluding the solution

void MyMethod(MyClass<MyConstraint> arg)
{
}

as well. In hind sight, as I reread the posts all along you were all
pointing me to this solution and in hindsight I just gotta say D'Oh.
 
NaughtDivisor said:
On closing, thank you very much all for being helpful.

Yes I do feel like an idiot. As I thought the solution is quite
simple I just got panicked and ran off in the wrong direction.

No need to feel like an idiot. It's just a case of stepping back, and
working out that it's worth learning about the general topic rather
than concentrating on one very specific question - which often isn't
the right question to be asking in the first place.

Hopefully you know significantly more about generics now than at the
start of this conversation :)
 
On closing, thank you very much all for being helpful.

Yes I do feel like an idiot. As I thought the solution is quite
simple I just got panicked and ran off in the wrong direction.

As Jon said, no need to feel like an idiot.

Or, if you do, you can at least take consolation that the rest of us have
those moments too. :) Heck, how about that code sample I posted for
you? I felt pretty dumb leaving those errors in it; I really should have
known better.

And remember: "DON'T PANIC!"

:)

Honestly, I think that's one of the most useful general-purpose pieces of
advice I could give. I think this experience expresses that lesson very
well. It's orders of magnitude harder to do something correctly when
stress has overwhelmed you. It's almost always more useful to leave the
problem and not come back to it until you've had a chance to calm down.

If a lion's chasing you, you might not have that option. But the decision
tree in that case is a lot simpler too. Otherwise, for humans living
today, we usually do have that option and should avail ourselves of it
whenever necessary. :)

Pete
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Back
Top