Generic Delegate Meltdown From Constraint

  • Thread starter Thread starter NaughtDivisor
  • Start date Start date
N

NaughtDivisor

I've just had a meltdown.


public delegate void
Unsubscribe_Delegate<T>(XmlPIDObjCollectionBase<T> bin) where T :
XmlPIDObjBase;
public Unsubscribe_Delegate<T> UnsubscribeDelegatesFromBinOwner;

Error:

The type or namespace name 'T' could not be found (are you missing a
using directive or an assembly reference?)


Solution? Work around? Am I wrong for cursing MS documentation for
not explaining how to deal with the above situation?
 
Sorry the class declaration for the generic parameter is below.

public class XmlPIDObjCollectionBase<T> : ICollection<T> where T :
XmlPIDObjBase
{
}
 
public delegate void
Unsubscribe_Delegate<T>(XmlPIDObjCollectionBase<T> bin) where T :
XmlPIDObjBase;
public Unsubscribe_Delegate<T> UnsubscribeDelegatesFromBinOwner;

Error:

The type or namespace name 'T' could not be found (are you missing a
using directive or an assembly reference?)

You've declared a generic type ("Unsubscribe_Delegate"). Then you've
tried to declare a variable using a concrete version of that type. But
you haven't provided a valid type parameter. In the declaration of
"UnsubscribeDelegatesFromBinOwner", you haven't provided an actual type
for the generic type parameter, you've simply written "T" again. And
since "T" isn't a defined type, you get the error saying that it can't be
found.

Only the type can be generic. Where you use it, you must provide an
actual type so that the compiler knows what to do.
Solution? Work around? Am I wrong for cursing MS documentation for
not explaining how to deal with the above situation?

The solution is to provide an actual type when using the generic type.
And yes, I think you're wrong for cursing the MS documentation. You are
fundamentally wrong in your use of the generic type, making a mistake that
I feel would be precluded by any reasonable reading of the MSDN
documentation on C# generics.

Pete
 
So whats the value of "T"? the example below shows T as MyClass:

public Unsubscribe_Delegate<MyClass> UnsubscribeDelegatesFromBinOwner;
 
NaughtDivisor said:
I've just had a meltdown.


public delegate void
Unsubscribe_Delegate<T>(XmlPIDObjCollectionBase<T> bin) where T :
XmlPIDObjBase;
public Unsubscribe_Delegate<T> UnsubscribeDelegatesFromBinOwner;

Error:

The type or namespace name 'T' could not be found (are you missing a
using directive or an assembly reference?)

Solution? Work around? Am I wrong for cursing MS documentation for
not explaining how to deal with the above situation?

Well, sort of.

You haven't really given enough context to this, but what type do you
expect UnsubscribeDelegatesFromBinOwner to be? You've got to specify a
type argument for T, effectively. The declaration (on the second line)
would be okay in a generic class where T is a type parameter, but not
otherwise. Alternatively, you could specify T:

public Unsubscribe_Delegate<int> UnsubscribeDelegatesFromBinOwner;

for example.

It's hard to help more without knowing more context, unfortunately.
 
Hmm..., perhaps a further explanation of the cause of my meltdown is
in order.

I need to define a delegate that excepts a generic type as a
parameter.

If I do as you suggest and declare my delegate as:


public delegate void
UnsubscribeDelegatesFromBinOwner_Delegate(XmlPIDObjCollectionBase<XmlPIDObjBase>
bin);
[XmlIgnore]
public UnsubscribeDelegatesFromBinOwner_Delegate
UnsubscribeDelegatesFromBinOwner;

I get the error:

cannot convert from 'XmlPIDObjCollectionBase<T>' to
'XmlPIDObjCollectionBase<XmlPIDObjBase>'

Once again the class declaration that I am trying to use as a
parameter is:

public class XmlPIDObjCollectionBase<T> : ICollection<T> where
T :
XmlPIDObjBase
{
}
 
NaughtDivisor said:
Hmm..., perhaps a further explanation of the cause of my meltdown is
in order.

I need to define a delegate that excepts a generic type as a
parameter.

Hang on - you need to be more careful here. There are two types of
declarations here. One declares a delegate *type*; the other declares a
*variable* of that type.

Now, I suggest that you declare the delegate outide any other types,
but obviously the variable will need to be declared within a type. Is
that type generic, or not? If not, you should know what kind of
delegate you need in a concrete manner.
 
To reiterate, I have a generic class with a constraint on it. I would
like to use this class as a parameter in a delegate. Every perm and
comb I have tried basically tells me I can not convert type <T> to the
type I am using as a constraint for my generic class. My
misunderstanding of generics regardless, what I am trying to do should
be simple but I can not find the correct way to implement it. Below
is pseudo code. Hopefully you all can be of help as to how I can work
around this problem.

public class XmlPIDObjCollectionBase<T> : ICollection<T> where T :
XmlPIDObjBase
{

}

public delegate void
Unsubscriber_Delegate<T>(XmlPIDObjCollectionBase<T> bin) where T :
XmlPIDObjBase;


pulbi class DoSomething
{
public Unsubscriber_Delegate<T>
UnsubscribeDelegatesFromBinOwner;
}

note: My fundemental misunderstanding of generics notwithstanding how
do I code this so that I do not keep on getting "can not convert
type.." errors. I have seen plenty of example in MS docs without the
use of constraints. Unfortunately none with the use of contraints.
Thans all for your help an interest.
 
NaughtDivisor said:
To reiterate, I have a generic class with a constraint on it. I would
like to use this class as a parameter in a delegate.

That's fine.
Every perm and
comb I have tried basically tells me I can not convert type <T> to the
type I am using as a constraint for my generic class. My
misunderstanding of generics regardless, what I am trying to do should
be simple but I can not find the correct way to implement it.
Below is pseudo code. Hopefully you all can be of help as to how I can work
around this problem.

public class XmlPIDObjCollectionBase<T> : ICollection<T> where T :
XmlPIDObjBase
{

}

public delegate void
Unsubscriber_Delegate<T>(XmlPIDObjCollectionBase<T> bin) where T :
XmlPIDObjBase;


pulbi class DoSomething
{
public Unsubscriber_Delegate<T>
UnsubscribeDelegatesFromBinOwner;
}

The problem is with the bottom class. What kind of BinOwner do you want
to unsubscribe from? You can't use a type parameter like that in a
nongeneric class.

The delegate decaration is fine, but you need to specify what the
concrete type of the variable is... or make the DoSomething class
generic in T as well (with a suitable constraint).
 
[...]
The problem is with the bottom class. What kind of BinOwner do you want
to unsubscribe from? You can't use a type parameter like that in a
nongeneric class.

The delegate decaration is fine, but you need to specify what the
concrete type of the variable is... or make the DoSomething class
generic in T as well (with a suitable constraint).

In other words (to make a specific example), you need to do either
something like this:

public class DoSomething
{
public Unsubscriber_Delegate<MyXmlPIDObj>
UnsubscribeDelegatesFromBinOwner;
}

where the class "MyXmlPIDObj" is a class that inherits "XmlPIDObjBase"
(obviously "MyXmlPIDObj" can be any appropriate type...it doesn't have to
have that name). Or you need something like this:

public class DoSomething<T> where T : XmlPIDObjBase
{
public Unsubscriber_Delegate<T> UnsubscribeDelegatesFromBinOwner;
}

Keeping in mind, of course, that the latter solution only delays the need
to specify _some_ actual type for the type parameter T later on. It won't
avoid that need altogether, it just avoids that need in the "DoSomething"
class.

Pete
 
Here is one of the perms and combs I have tried that may make things
more clear as to what I am trying to do:

public delegate void
UnsubscribeDelegatesFromBinOwner_Delegate(XmlPIDObjCollectionBase<XmlPIDObjBase>
bin);

public class XmlPIDObjCollectionBase<T> : ICollection<T> where T :
XmlPIDObjBase
{

public UnsubscribeDelegatesFromBinOwner_Delegate
UnsubscribeDelegatesFromBinOwner;

public XmlPIDObjCollectionBase(BinOwner binOwner)
{
binOwner.SubscribeDelegatesForBinOwner(this);


}
public void RemoveFromBinOwner()
{

:
:
:
if (this.UnsubscribeDelegatesFromBinOwner != null)
UnsubscribeDelegatesFromBinOwner(this);

COMPILER ERROR:
cannot convert from 'XmlPIDObjCollectionBase<T>' to
'XmlPIDObjCollectionBase<XmlPIDObjBase>'

}

}



public class BinOwner
{

private void
SubscribeDelegatesForBinOwner<T>(XmlPIDObjCollectionBase<T> bin) where
T : XmlPIDObjBase
{
bin.UnsubscribeDelegatesFromBinOwner +=
this.OnUnsubscribeDelegatesFromBinOwner;
}

public void
OnUnsubscribeDelegatesFromBinOwner<T>(XmlPIDObjCollectionBase<T> bin)
where T : XmlPIDObjBase
{
:
:
:

bin.UnsubscribeDelegatesFromBinOwner -=
this.UnsubscribeDelegatesFromBinOwner;


}
}


I am stumped and ready to give up but I can not believe that what is
seemingly a very simple thing to do can not be done. Please help. I
am past my meltdown but I also have three holes in my office walls and
am now most likely going to miss a deadline.
 
Here is one of the perms and combs I have tried that may make things
more clear as to what I am trying to do:

Note that this example has the same problem as your previous
misunderstanding of what I was trying to suggest (and which Jon tried to
clarify).

When I suggested that you need to use a concrete type for the type
parameter eventually, my point wasn't that you should just put it in where
convenient. You still need to comply with the chain of generic
declarations.

To explain the error you're getting now:
[...]
if (this.UnsubscribeDelegatesFromBinOwner != null)
UnsubscribeDelegatesFromBinOwner(this);

COMPILER ERROR:
cannot convert from 'XmlPIDObjCollectionBase<T>' to
'XmlPIDObjCollectionBase<XmlPIDObjBase>'

This is because generics don't allow covariance. The only thing that can
successfully be cast to an "XmlPIDObjCollectionBase<XmlPIDObjBase>" is
either an instance of that class, or one that inherits _from that class_..
Note that something that inherits from
XmlPIDObjCollectionBase<XmlPIDObjBase> will be declared like this:

class SomeClass : XmlPIDObjCollectionBase<XmlPIDObjBase>

or even:

class SomeClass<T> : XmlPIDObjCollectionBase<T>

where T _is_ XmlPIDObjBase when SomeClass is actually declared. It's not
sufficient for T to simply inherit XmlPIDObjBase in that case; it would
actually have to be XmlPIDObjBase.

For more details on that, just Google this newsgroup for "generic
covariance". There's been lots of discussion on it in previous threads.

Now, as far as what you're actually doing, you still haven't really
explained _what_ you want to do. You keep posting code that illustrates
_how_ you've tried to do it, but since none of those code examples
actually work, they really aren't all that good at illustrating the "what".

If I have successfully interpreted your intent, it's my opinion that you
don't want to use a delegate at all. An interface may be a better way of
dealing with the situation, and it's possible that you could write the
code just to call the method in question directly. I think that using a
delegate is just making the code more difficult to implement, and it will
likely make the code harder to understand later.

However, if you really feel tied to a delegate-based implementation, maybe
something like this example would work for you:

using System;

namespace TestGenericSubscriber
{
class Program
{
class MyBase
{
}

class MyOwned<T> where T : MyBase
{
public delegate void UnsubscribeDelegate(MyOwned<T> owned);

private UnsubscribeDelegate _unsubscribe;

public MyOwned(UnsubscribeDelegate unsubscribe)
{
Console.WriteLine("creating MyOwned instance");
_unsubscribe = unsubscribe;
}

public void Remove()
{
Console.WriteLine("removing MyOwned instance");
if (_unsubscribe != null)
{
_unsubscribe(this);
}
}
}

class MyOwner
{
MyOwned<MyBase> _owned;

public void MakeOwned()
{
Console.WriteLine("making _owned");

// This next line is probably the most important for you
// to understand. In addition to the declaration of the
// local variable in which the reference to the
// instance is stored, this is the only other place
// that an actual type is supplied for the generic type
// parameter. In addition, it is at this point that you
// _must_ provide an actual type, since the class and
// method containing this code is _not_ generic, and so
// have no generic type parameters to take the place of
// an actual type.

_owned = new MyOwned<MyBase>(UnsubscribeHandler<MyBase>);
}

public void RemoveOwned()
{
Console.WriteLine("removing _owned");
_owned.Remove();
_owned = null;
}

private void UnsubscribeHandler<T>(MyOwned<T> owned) where T :
MyBase
{
Console.WriteLine("unsubscribe handler");
}
}

static void Main(string[] args)
{
MyOwner owner = new MyOwner();

owner.MakeOwned();
owner.RemoveOwned();
Console.ReadLine();
}
}
}

Note that rather than passing an instance of the class containing the
method to the constructor of the "owned" class, I just pass the delegate
instance itself. There is no reason to use a delegate if you are passing
the instance of the class, since if you have a reference to the instance,
and the method you're trying to call is accessible, you can just call the
method directly rather than going through the delegate.

So a delegate-based solution only makes sense if you don't have the
instance to the class containing the called method. Thus, this example
was written that way.

Because of this change, you'll note that the "subscribe" method (which
presumably would have been called from the code where the owned object is
instantiated) just isn't even there anymore. Rather than having the
constructed class call back to the owning class, the owning class just
passes the necessary delegate instance. No calling back to the owning
class, thus no need for the subscribe method at all.

On the assumption that your owned class can only have one owner at a time,
I've changed the syntax used somewhat, by not using the multicast aspect
of the delegate at all. It's simply assigned and cleared. But there's no
reason you couldn't use the multicast syntax if you wanted to. It would
follow basically the same organization (and the same requirement that you
at some point use an actual class to define what type is being used to
create the generic type instance).

Of course, as I mentioned before, it seems to me that if you have the
luxury of passing an instance of the class containing the called method,
then you might as well just store that instance reference and call the
method directly when needed. That's the simplest way to write the code,
and it will be the most understandable. This is especially true if you
really do have the "owner/owned" relationship that your example implies
and there will only be one instance "subscribed" to the owned object at a
time.
I am stumped and ready to give up but I can not believe that what is
seemingly a very simple thing to do can not be done. Please help. I
am past my meltdown but I also have three holes in my office walls and
am now most likely going to miss a deadline.

For what it's worth, your frustration seems to have extended to preventing
you from posting a good question. It's not that the information you seek
isn't worthwhile. It's that how you present that question has been poor..

One of the most important things, in all endeavors, is Douglas Adams's
famous admonition: DON'T PANIC! That's true here too. If you need to
blow off steam, go do that (but I don't recommend punching holes in your
walls). If you need an answer to a question, ask the question. But don't
ask a question while you still need to blow off steam. The first step to
getting anything done is to calm down. Otherwise nothing will work. :)

Pete
 
Thank you for the informative kind and polite response.

What really got going was that I could not do something like:



public delegate void XFunc_Delegate<T>(BinBase<T> bin) where T :
XmlPIDObjBase;

public XFunc_Delegate<T> XFunc where T : XmlPIDObjBase;


Why the compiler will not except this I think is more a matter of
Visual Studio 2.0 not having this implementation built in and not much
to do with violating covariance. Admittedly I have not delved into
DotNets implementation of generics but from the surface this looks
like it logically should be compilable -- as long as folks in Redmond
had the time to build it into the compiler.

The generic delegate examples for MS Doc have lots of examples of
generic delegates excepting a non-constrained generic class as an
argument but have nothing to say about a generic delegate that excepts
a contrained generic class as an argument. If it can not be done I
wish they would just say so. If it can they should provide an
example.

I still am in disbelief that there is no way to accomplish this. It
is not so much a programming issue on my part as trying to find the
way through a brick wall. I imagine there will be times in the future
where I will want this type of functionality and I am stubborn to a
fault when I come across something that logically makes sense but just
doesn't seem to work. I do not mind if it has not been implemented I
would just like to know so I do not spend a day trying to di the
unimplemented.

As to my poorly worded question and example, what can I say, I
honestly thought I was just missing the correct syntax and that there
would be simple solution and I thought the title would be enough to
get folks on the correct track.

Thanks again

PS. I still think there has to be away to except a constrained
generic class as an argument in a delegate without going through a
bunch of hops which is really all I concerned about but thanks for the
example. As to the owner and the owned, the owned can be "owned" by
more the one "owner". Using delegates gives a lot of flexibility for
multicasting and threading, and keep exposure of properties to a
minium - which makes me queasy whenever storing object references.
Just does not feel right to me in a loosely coupled kind of way.

Thanks again.

P.P.S. I really did not kick any holes in my office walls but I
probably will miss my deadline.
 
Thank you for the informative kind and polite response.

What really got going was that I could not do something like:

public delegate void XFunc_Delegate<T>(BinBase<T> bin) where T :
XmlPIDObjBase;

public XFunc_Delegate<T> XFunc where T : XmlPIDObjBase;


Why the compiler will not except this I think is more a matter of
Visual Studio 2.0 not having this implementation built in and not much
to do with violating covariance.

VS 2.0 doesn't even support .NET. But, whatever version of VS you're
using, the failure of the above to compile doesn't have anything to do
with covariance. That was an issue with respect to your previous line of
code, but you have a completely different error here.

The thing you keep missing is that you can only use type parameters to
declare the generic class or method itself. When you declare an actual
usage of that class or method, you _must_ have an actual type provided
where the type parameter is.

I'm having a hard time understanding why you're confused about this. You
wouldn't demand that the compiler allow you to write code that calls a
function without specifying some resolvable value for each parameter,
would you? Why do you demand that the compiler allow you to write code
that tries to use a generic class or method without specifying some
resolvable value for the type parameter of that generic class or method?
Admittedly I have not delved into
DotNets implementation of generics but from the surface this looks
like it logically should be compilable -- as long as folks in Redmond
had the time to build it into the compiler.

Well, I don't know what to say. You're just wrong about "it logically
should be compilable". It wouldn't make any sense to compile code like
that. Generics allow you to define "generic" types and methods for use in
_actual_ code. But the generic types and methods aren't actually usable
code. They only become usable when you use a generic type or method in
conjunction with an actual type specified for each parameter of the
generic type or method.

You can nest the use of generic types or methods, creating a hierarchy of
generic usages. But the top-most usage in that hierarchy _must_ specify
an actual type. Just as the top-most call in a hierarchy of calls to
functions must specify an actual value, even if the calls below that
top-most call simply use passed in values.
The generic delegate examples for MS Doc have lots of examples of
generic delegates excepting a non-constrained generic class as an
argument but have nothing to say about a generic delegate that excepts
a contrained generic class as an argument. If it can not be done I
wish they would just say so. If it can they should provide an
example.

Well, again, it seems to me that you are not being very clear about your
question. You most certainly can declare a _generic_ delegate type that
constrains the type parameter. For example:

delegate MyDelegate<T>(T t) where T : BaseClass;

But when you get around to using it, you are required to supply an actual
type for that parameter (one that fulfills the constraint, of course).

I haven't had a chance to look in MSDN for an example, and it's possible
that indeed they don't offer an example of that particular scenario. But
I know for a fact that MSDN does discuss the use of constraints, and it is
possible infer the proper syntax to declare such a generic delegate type
from the examples they do provide.
I still am in disbelief that there is no way to accomplish this.

Accomplish what? So far, you've received a number of replies explaining
how to do _something_. They all include either direct information about
how to successfully do something, if not actual code that does that
something. You haven't said that those replies _don't_ answer your
question, so what is "this" that you can't do?
It is not so much a programming issue on my part as trying to find the
way through a brick wall.

No offense, but trying to get you to be more specific about what your
question is feeling a bit like that "way through a brick wall" of which
you speak.
I imagine there will be times in the future
where I will want this type of functionality and I am stubborn to a
fault when I come across something that logically makes sense but just
doesn't seem to work. I do not mind if it has not been implemented I
would just like to know so I do not spend a day trying to di the
unimplemented.

If you would just explain clearly what behavior it is you want, there is
no doubt in my mind that someone could offer an example of how to
implement that behavior. But in spite of us providing information,
including the working code that I offered that does _exactly_ what the
code you posted would have done had it been valid code, you remain
unsatisfied.

But make no mistake: this lack of satisfaction is very unlikely to do with
any limitation of the language. It's just that you still haven't provided
a clear explanation of what behavior you want to do.
As to my poorly worded question and example, what can I say, I
honestly thought I was just missing the correct syntax and that there
would be simple solution and I thought the title would be enough to
get folks on the correct track.

Have you looked at the subject line that you provided? We can throw out
"Meltdown", since that's not a technical term. What's left is "generic
delegate from constraint". How are we supposed to glean from that what it
is exactly you're trying to do?
Thanks again

PS. I still think there has to be away to except a constrained
generic class as an argument in a delegate without going through a
bunch of hops which is really all I concerned about but thanks for the
example.

What hops? You declare a generic delegate with a constraint in exactly
the same way you declare any other generic with a constraint.
As to the owner and the owned, the owned can be "owned" by
more the one "owner". Using delegates gives a lot of flexibility for
multicasting and threading, and keep exposure of properties to a
minium - which makes me queasy whenever storing object references.
Just does not feel right to me in a loosely coupled kind of way.

Well, the pattern you posted is simply confusing. I would not use the
name "owner" if you can have multiple owners. "Observer" or similar might
be a better choice. As for the use of a delegate, IMHO you would be
better off declaring an event to which the "owner" (or whatever) can
subscribe to directly. That's a standard pattern in .NET, and this
business of having the "owned" (or whatever) calling a public method on
the "owner" just for the purpose of subscribing to what is essentially an
event (even if you don't use an actual event) inserts an unnecessary and
confusing level of indirection.

But regardless, none of this precludes the use of generics. You just need
to use them correctly. If you never give the compiler an actual type for
a generic parameter at some point, it will never be able to resolve the
generic type as something useful.

Pete
 
Sorry...a couple of clarifications:


Just to be clear: the problem with the above is that a constraint is only
applicable to the declaration of a generic type or method. It's
completely nonsense to use a constraint in an actual _use_ of a generic
type or method. And you can only specify "T" as the type parameter if T
actually is resolvable as an actual type. That would be a real type, or
if you are using the generic type or method in another generic type or
method, you could also specify a type parameter from that other generic
type or method (since in the context of the declaration of that generic
type or method, the type parameter is used just as an actual type would
be).

Also...
[...]
Well, again, it seems to me that you are not being very clear about your
question. You most certainly can declare a _generic_ delegate type that
constrains the type parameter. For example:

delegate MyDelegate<T>(T t) where T : BaseClass;

Of course that's an invalid declaration, since I forgot to specify a
return type for the delegate type. My mistake. I don't think it should
affect your understanding of the example, since the constraint is the
important part. But I did want to clear that up too.

Pete
 
Thanx Pete,

You hit the nail exactly on the head:

Quote:

EndQuote

So exactly how do you supply the actual type for that parameter when
used as an argument in a delegate. I have tried everything I can
think of and nothing works. I assume there is a way thus I have spent
a day looking. I am now sorry for posting code that obviousely does
not work as it has done nothing but confuse the issue - but if I knew
the code to supply the type for a paramater when using a contrained
generic class as a argument in a delegate I would not have posted in
the first place.

So the million dollar question is: How do you supply the type for a
constrained generic class when used as an argument in a delegate.

Ie.

public class XmlPIDObjCollectionBase<T> : ICollection<T> where T :
XmlPIDObjBase
{
}


public delegate void XFunc_Delegate<T>(BinBase<T> bin) where T :
XmlPIDObjBase;

public XFunc_Delegate<T> XFunc where T : XmlPIDObjBase; DOES NOT
WORK
public XFunc_Delegate<T> XFunc; DOES NOT WORK
public XFunc_Delegate XFunc; DOES NOT WORK


public delegate void XFunc_Delegate<T>(BinBase<T> bin) where T :
XmlPIDObjBase;

public XFunc_Delegate<XmlPIDObjBase> XFunc DOES NOT WORK, as you
mentioned this type of implied inheritance is incorrect
public XFunc_Delegate<T> XFunc; DOES NOT WORK, no should it but
that is not the point,

I am not interested in the reasons the above does not work, that is
not the point. I was and am trying to illustrate that I am at a loss
for how to supply a type for a constrained generic class used in an
argument in a delegate

So while being helpful and greatly appreciated, no one has said yes
this can be done and this is how you do it or no there is not way to
do this. The issue in the post has been skirted as in all the MS Docs
that I have read. I take full responsibiliy for not wording the post
correctly but I really did not think this was going to be so tortuose.
 
[...]
So exactly how do you supply the actual type for that parameter when
used as an argument in a delegate. I have tried everything I can
think of and nothing works. I assume there is a way thus I have spent
a day looking. I am now sorry for posting code that obviousely does
not work as it has done nothing but confuse the issue - but if I knew
the code to supply the type for a paramater when using a contrained
generic class as a argument in a delegate I would not have posted in
the first place.

So the million dollar question is: How do you supply the type for a
constrained generic class when used as an argument in a delegate.

The question looks like plain English, but I'm not sure I can parse it.
The first part, "how do you supply the type for a constrained generic
class" seems okay, and is equivalent to "how do you supply the type for a
generic class", since the constraint doesn't change how you specify the
type.

But the second part, "when used as an argument in a delegate", to what
does that refer? When _what_ is used as an argument in a delegate? Do
you mean when the type parameter for the generic delegate is used as the
type for an argument in the argument list for the delegate?

If so, then the second part is just as superluous as the use of the word
"constrained", as you always supply the type the same way, regardless of
how it's used. Specifically, if you have a generic type named "Foo", the
type is _always_ supplied by putting angle brackets after the name "Foo"
and listing the necessary type parameters within the angle brackets, in
the correct order, separated by commas.

If not, then you need to explain that second part more clearly. As it is,
it's missing whatever noun or pronoun that would allow us to understand it.

Assuming I've managed to parse the question correctly, then as an example:
if you have just one type parameter named "MyType", and you want to supply
it to a generic type named "Foo", you write the whole thing as
"Foo<MyType>".

You do it that way regardless of whether or not the generic type uses a
constraint on the type parameter, and you do it that way even if the type
parameter is used as an argument in the argument list for a generic
delegate type.
Ie.

public class XmlPIDObjCollectionBase<T> : ICollection<T> where T :
XmlPIDObjBase
{
}

Declares a generic class type named "XmlPIDObjCollectionBase".
public delegate void XFunc_Delegate<T>(BinBase<T> bin) where T :
XmlPIDObjBase;

Declares a generic delegate type named "XFunc_Delegate".
public XFunc_Delegate<T> XFunc where T : XmlPIDObjBase; DOES NOT
WORK

Why should it? The declaration isn't a valid declaration of a generic
delegate type, because it's missing things like the return type and the
argument list. But it's also not a valid declaration of a variable using
a generic delegate type, because T is undefined and, at least as
important, a constraint (i.e. "where T : XmlPIDObjBase") is legal only
when declaring a generic type or method. It is NOT legal when you _use_ a
generic type or method.
public XFunc_Delegate<T> XFunc; DOES NOT WORK

Again, why should it? If it doesn't work, that's because T is undefined
at that point. You can't declare a variable of type "XFunc_Delegate<T>"
here any more than you can declare a variable of "T". Would you expect
this line to work:

public T XFunc;

? If not, then why would you expect the other line to work?

If you _do_ expect my example above to work, then if you could explain why
you would expect it to work, that might help understand whatever is flawed
in your reasoning, so that we can better answer your question.
public XFunc_Delegate XFunc; DOES NOT WORK

Why should it? You can't use a generic type without specifying the type
parameter for the type.
public delegate void XFunc_Delegate<T>(BinBase<T> bin) where T :
XmlPIDObjBase;

This is identical to your previous decalaration of the generic delegate
type named "XFunc_Delegate".
public XFunc_Delegate<XmlPIDObjBase> XFunc DOES NOT WORK, as you
mentioned this type of implied inheritance is incorrect

The only thing I see wrong with that declaration is that you're missing a
semi-colon. Why do you say it doesn't work?
public XFunc_Delegate<T> XFunc; DOES NOT WORK, no should it but
that is not the point,

You're right, it won't work, and for the same reason it didn't work
above. But if that's not the point, why are you posting it as an example?
I am not interested in the reasons the above does not work, that is
not the point.

If it's not the point, then why post the examples?
I was and am trying to illustrate that I am at a loss
for how to supply a type for a constrained generic class used in an
argument in a delegate

I don't see how examples that don't work, and for which you don't care why
they don't work, could help illustrate whatever point it is you're trying
to make. Perhaps it would be better for you to stick with the problem
statement, at work toward fixing it so that it makes more sense (see my
comments at the top of this post for feedback regarding that problem
statement and why it's not helpful at the moment, hopefully leading you to
provide a problem statement that _is_ helpful).
So while being helpful and greatly appreciated, no one has said yes
this can be done and this is how you do it or no there is not way to
do this.

No one could have yet. You still have not successfully conveyed what
"this" is. There's no way for anyone to tell you "yes" or "no" you can do
"this", until we understand what "this" is.
The issue in the post has been skirted as in all the MS Docs
that I have read. I take full responsibiliy for not wording the post
correctly but I really did not think this was going to be so tortuose.

I think we've been reasonably patient. We're not torturing your on
purpose. But it would help if you would look more closely at the
statements we've made regarding our inability to understand what it is
exactly you're trying to do. Even as you wrote "I am now sorry for
posting code that obviousely does not work as it has done nothing but
confuse the issue", you then proceeded to include a bunch more examples of
code that doesn't work, and then wrote that "I am not interested in the
reasons the above does not work".

I've already explained that code that doesn't work is not helpful in
understanding what you are trying to do. Especially when that code is
nonsensical (in _some_ cases, posting code that would work in another
language but not in C#, for example, could help...but that's not the case
here).

Please try to focus, sticking to precisely the point you're trying to
solve, don't post code that's not relevant, and _do_ try to reword your
question so that it's clear what you're actually asking, taking into
account our own feedback regarding what about your question we don't
understand.

Pete
 
I am not interested in the reasons the above does not work, that is
not the point.

No, it's exactly the point. Until you're willing to take a step back
and examine your understanding of generics, you won't be able to even
properly formulate the question - and by the time you can, you won't
need to.
So while being helpful and greatly appreciated, no one has said yes
this can be done and this is how you do it or no there is not way to
do this.

That's because you've not been clear on what you really want to do.
You've shown the code you want to work, and clearly it *doesn't* work,
but without being clear about the larger aim, we won't be able to help
further.

To be specific, you haven't explained why you want to declare a
delegate field in a generic way within a non-generic class. You haven't
explained how you want it to actually behave.

The constraint is irrelevant to your problem - the problem is that
you're trying to declare a generic delegate field in a non-generic
class. That won't work whether there are constraints or not.
 
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?

2.) How does one pass, as an argument, a constrained generic class to
a delegate field in a non-generic class?
 
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?

A class? Or an instance of a class? Remember, a class is an instance as
well, of the Type class. One problem in this thread has been that your
questions have been ambiguous, and that's a problem here too.

Assuming you're actually talking about an instance of a generic class, the
answer is "the same way you'd pass it to a generic class". And the fact
that the generic class is constrained is irrelevant. Whether the generic
class is constrained or not, you need a fully-qualified instance of the
generic class.

Some examples:

class MyConstraint { }

class MyClass<T> where T : MyConstraint { }

class MyOtherClass
{
// 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()
{
// In either case, you must have a fully-qualified,
// instantiated instance of the generic class itself

MyMethod(new MyClass<MyConstraint>());

MyMethod<MyConstraint>(new MyClass<MyConstraint>());
}
}
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 arguments to fields. You only pass them to methods.
Again, ambiguity rears its ugly head.

If you're asking how do you pass as an argument a generic class when
invoking a delegate instance, then the answer is the same as above, except
that you've got a delegate type field instead of an explicit method. And
again, the constraint is irrelevant.

For example:

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>());
}
}

Note that in none of the above examples, even though I've declared the
various generics with a constraint, the constraint never comes into play
with respect to actually _using_ the generic (other than, of course, to
require that I use MyConstraint or a derived class as the type
parameter). The constraint is completely irrelevant with respect to the
specific use of the generic types or methods.

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