dek
dek

Reputation: 85

How to add constraints to non generic methods or something close to this feature

Given a Generic class with some methods. Based on the "Generic class of type", I would like to use the appropriate methods. Is there a way to achieve this functionality?

for example:

public interface IType {}
public class TypeA : IType { }
public class TypeB : IType { }

public class Worker<T> where T : IType
{
    private string _msg;

    public Worker<T> DoWorkA(string input) where T : TypeA
    {
        _msg = input;
        return this;
    }
    public Worker<T> DoWorkA2(string input) where T : TypeA
    {
        _msg += input;
        return this;
    }
    public Worker<T> DoWorkB(string input) where T : TypeB
    {
        _msg = input;
        return this;
    }

    public void DoWork()
    {
        Console.WriteLine(_msg);
    }
}

// usage

// this should work

var worker = new Worker<TypeA>().DoWorkA("Doing").DoWorkA2(" A class work");
worker.DoWork();

// this should NOT work

var worker = new Worker<TypeA>().DoWorkB("Doing B class work");
worker.DoWork();

Upvotes: 0

Views: 64

Answers (3)

dek
dek

Reputation: 85

Thanks to you all for your help. I went with @Sefe suggestion about using Extension Methods. Thanks so much @Sefe for even providing me with an example. This is what I finally came up with that does exactly what I want.

public interface IType { }
public class TypeA : IType { }
public class TypeB : IType { }

public class Worker<T> where T : IType
{
    public string Message { get; set; }

    public void DoWork()
    {
        Console.WriteLine(Message);
    }
}

public static class WorkerExtensions
{
    public static Worker<TypeA> DoWorkA1(this Worker<TypeA> w, string input)
    {
        w.Message = input;
        return w;
    }
    public static Worker<TypeA> DoWorkA2(this Worker<TypeA> w, string input)
    {
        w.Message += input;
        return w;
    }
    public static Worker<TypeB> DoWorkB(this Worker<TypeB> w, string input)
    {
        w.Message += input;
        return w;
    }
}

And this is the usage:

var workerA = new Worker<TypeA>().DoWorkA1("Doing").DoWorkA2(" A class work");
workerA.DoWork();

var workerB = new Worker<TypeB>().DoWorkB("Doing B Class Work");
workerB.DoWork();

Upvotes: 0

Sefe
Sefe

Reputation: 14017

You might want to switch to a non-generic class with generic methods. There you can add individual constraints:

public class Worker
{
    private string _msg;

    public Worker<T> DoWorkA<T>(string input) where T : TypeA
    {
        _msg = input;
        return this;
    }
    public Worker<T> DoWorkB<T>(string input) where T : TypeB
    {
        _msg = input;
        return this;
    }

    public void DoWork()
    {
        Console.WriteLine(_msg);
    }
}

UPDATE:

According to your comment you don't want to include type parameters in each call to the generic methods. That is not an issie, if you pass instances of your class to the worker methods, because the type can then be inferred:

public class Worker
{
    public Worker<T> DoWorkA<T>(T value) where T : TypeA
    {
        _msg = input;
        return this;
    }
    public Worker<T> DoWorkB<T>(T value) where T : TypeB
    {
        _msg = input;
        return this;
    }
}

In this case the type parameter can be inferred:

Worker worker = new Worker();
TypeA a = new TypeA();
worker.DoWorkA(a);

You could do it also with extension methods:

public static class Worker
{
    public static Worker<T> DoWorkA<T>(this T value) where T : TypeA
    {
        _msg = input;
        return this;
    }
    public static Worker<T> DoWorkB<T>(this T value) where T : TypeB
    {
        _msg = input;
        return this;
    }
}

Which you can call like this:

TypeA a = new TypeA();
a.DoWorkA();

Upvotes: 2

KMoussa
KMoussa

Reputation: 1578

You can do a generic interface that accepts T and have 2 implementations: one for TypeA and one for TypeB, possibly with a base class that holds common functionality:

public interface IWorker<T>
{
    IWorker<T> GetWorker();
}

public class BaseWorker
{
    public void DoWork() { }
}

public class WorkerA : BaseWorker, IWorker<TypeA> {}

public class WorkerB : BaseWorker, IWorker<TypeB> {}

Upvotes: 0

Related Questions