1

Suppose I have a class like so:

public class MyClass<T> where T : BaseClass, new()
{
    public Boolean DoWork()
    {
        // do the work, obviously.
    }
}

And in some method I need to DoWork() on some MyClass<T> for which I don't need to know T. As far as I know, I need to refer to my MyClass<T> parameter and reiterate the constraints for T, like so:

public void DoLotsOfWork(MyClass<T> item) where T : BaseClass, new()
{
    // do some work

    // no need to know what T is here:
    item.DoWork();

    // maybe do some other work.
}

Can method DoLotsOfWork() refer to MyClass<T> without reiterating the constraints on T? (Or possibly even knowing about T?)

svidgen
  • 13,744
  • 4
  • 33
  • 58
  • In this case why would dolotsofwork not be a member? – rerun Feb 25 '14 at 18:45
  • 2
    @rerun Perhaps it's in another assembly written years after `MyClass` is defined. Why is your method that does work on a `List` not an instance method of `List`? – Servy Feb 25 '14 at 18:45
  • If those are true sure. Doesn't mean that they are. If it can be made a member its any easy change. If it is in another assembly then you don' have a lot of options. – rerun Feb 25 '14 at 18:48
  • 1
    @rerun There's a class defining how to do some type of work, and then there's another method that uses the class to do some work. It's entirely logical that they be separate. There's no reason that they should be stuck together. Classes are created to be used. You don't want to just have one monolithic class that represents your entire program. – Servy Feb 25 '14 at 18:49

3 Answers3

2

The way to handle this is to make DoLotsOfWork generic.

public void DoLotsOfWork<T>(MyClass<T> item) where T : BaseClass, new()
{
    // do some work

    // no need to know what T is here:
    item.DoWork();

    // maybe do some other work.
}

You cannot refer to a MyClass type, and access any information specific to that type, without providing any generic argument, no. (At least not using static typing; you'd need to move to things like reflection to do that.)

Servy
  • 202,030
  • 26
  • 332
  • 449
  • The constraints can probably be removed here as well. – Magus Feb 25 '14 at 18:43
  • @Magus They cannot. It wouldn't compile without them. Otherwise you could provide this method with a type that isn't suitable for `MyClass`. – Servy Feb 25 '14 at 18:44
  • Technically that makes the answer 'no' then, considering his last line. This is definitely the way to go about it, though. I'd mistakenly considered this a member. – Magus Feb 25 '14 at 18:47
  • Contrary to my *hopes*, this is the answer I was expecting. (Trying to "bless" some legacy code with some new "magic" without touching *too much* of the legacy stuff.) – svidgen Feb 25 '14 at 18:55
  • Perhaps I'm better off injecting an interface. (Or scrapping the layers of legacy BS!) – svidgen Feb 25 '14 at 18:56
2

If you can alter the MyClass<T> class definition, then you can make it derive from a non-generic base class that specifies your method as abstract:

public abstract class MyClassBase
{
    public abstract Boolean DoWork();
}

public class MyClass<T> : MyClassBase where T : BaseClass, new()
{
    public override Boolean DoWork()
    {
        // do the work, obviously.
    }
}

Then, use this base class as the parameter type:

public void DoLotsOfWork(MyClassBase item)
{
    item.DoWork();
}

This approach is used in the .NET Framework, where Task<Result> derives from Task. The latter contains the members that do not rely on the generic type, such as Wait().

Douglas
  • 53,759
  • 13
  • 140
  • 188
  • I especially like that you can give the non-generic abstract class the same name as the generic class. – gilly3 Feb 25 '14 at 19:21
0

You could declare the parameter as dynamic:

public void DoLotsOfWork(dynamic item)
{
    // do some work

    // no need to know what T is here:
    item.DoWork();

    // maybe do some other work.
}

Makes your code prettier, but there is a performance hit. However, if you call DoLotsOfWork several times in the life of the app, you should only take a performance hit on the first call, so the cost should be negligible.

Community
  • 1
  • 1
gilly3
  • 87,962
  • 25
  • 144
  • 176