Moussamoa
Moussamoa

Reputation: 427

Generic class with method specific to a certain type in C#

I have a generic class that I use to define a range of values. I would like to have a method only for int type which returns a random value in this range. How can I have a method for a specific type in a generic class ? Is it possible at all ? Here is my class :

public class Range<T> where T : IComparable<T>
{
    public T Minimum { get; set; }
    public T Maximum { get; set; }

    public Range(T Minimum, T Maximum)
    {
        this.Minimum = Minimum;
        this.Maximum = Maximum;
        if (!IsValid())
        {
            this.Minimum = Maximum;
            this.Maximum = Minimum;
        }
    }

    public bool IsValid()
    {
        return this.Minimum.CompareTo(this.Maximum) <= 0;
    }
}

Upvotes: 0

Views: 362

Answers (3)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249556

You can use the way static fields work in generics to specify a custom delegate that will serve as the implementation for the method:

public class Range<T> where T : IComparable<T>
{
    public T Minimum { get; set; }
    public T Maximum { get; set; }
    // GetRandomNumber specific implementation, the field can have a different value for a specific `T`
    public static Func<Range<T>, T> GetRandomNumberHelper = (self) => throw new NotImplementedException("Not implemented for type " + typeof(T).FullName);
    public T GetRandomNumber()
    {
        return GetRandomNumberHelper(this);
    }

}
public class Program
{
    public static void Main()
    {
        // Assign the delegate in a static constructor or a main
        Range<int>.GetRandomNumberHelper = self => new Random().Next(self.Minimum, self.Maximum);
    }
}

Another option would be to used a derive type for a certain T, as suggested in another answer here. The problem is that there is no way to prevent at compile time someone from creating a new Range<int>() instead of new IntRange(), this may be a problem or not depending on your use case.

A third option would be to use an extension method if you don't need to access the method for a random T:

public static class RangeExt
{
    public static int GetRandomNumberHelper(this Range<int> self)
    {
        return new Random().Next(self.Minimum, self.Maximum);
    }
}

The problem here is that a function that takes a parameter of type Range<T> will not be able to access the method, only on parameters of type Range<int> will this method appear. This may be a problem depending on your use case

Upvotes: 0

Ashkan Mobayen Khiabani
Ashkan Mobayen Khiabani

Reputation: 34152

You could do as Yair Halberstadt says or if you insist on having the function in your class you can do it like this:

 public class Range<T> where T : IComparable<T>
    {
        public T Minimum { get; set; }
        public T Maximum { get; set; }

        public Range(T Minimum, T Maximum)
        {
            this.Minimum = Minimum;
            this.Maximum = Maximum;
            if (!IsValid())
            {
                this.Minimum = Maximum;
                this.Maximum = Minimum;
            }

        }
        public int GetRandomNumber()
        {
            if (typeof(T) == typeof(int))
            {
                return new Random().Next(Convert.ToInt32(Minimum), Convert.ToInt32(Maximum));
            }
            else
                throw new Exception("Given type is not integer.");
        }
        public bool IsValid()
        {
            return this.Minimum.CompareTo(this.Maximum) <= 0;
        }
    }

Here is the DEMO

Upvotes: 1

Yair Halberstadt
Yair Halberstadt

Reputation: 6821

just inherit from Range<int>

 public class IntRange : Range<int>
    {
        public IntRange(int Minimum, int Maximum) : base(Minimum, Maximum)
        {
        }
        public void MySpecificToIntMethod()
        {}
    }

Upvotes: 2

Related Questions