Avi Turner
Avi Turner

Reputation: 10456

C# generic constraint for Type to be castable

Is there a way with C# generics to limit a type T to be castable from another type?

Example:
Lets say I am saving information in the registry as a string, and when I restore the information I would like to have a function that looks something like that:

static T GetObjectFromRegistry<T>(string regPath) where T castable from string 
{
    string regValue = //Getting the registry value...
    T objectValue = (T)regValue;
    return objectValue ;
}

Upvotes: 14

Views: 5466

Answers (4)

Jessie Koffi
Jessie Koffi

Reputation: 176

While the literal answer is no, the correct answer in the spirit of the question is yes.


Test test = new Test();
test.TestMethod();

class A
{
    public string someField;
}

class B : IConvertibleFrom<A>
{
    public string convertedField;

    public void TakeDataFrom(A a)
    {
        this.convertedField = a.someField;
        //etc
    }
}

class C
{
}

interface IConvertibleFrom<T>
{
    void TakeDataFrom(T t);
}

class Test  
{

    // here is our constraint
    public T FromA<T>() where T: IConvertibleFrom<A>, new()
    {
        var a = new A();
        a.someField = "it works";
        T t = new T();
        t.TakeDataFrom(a);
        return t;
    }

    public void TestMethod()
    {
        var b = FromA<B>();
        Console.WriteLine(b.convertedField); // prints "it works"
        // var c = FromA<C>(); // Compiler error because C does not implement IConvertibleFrom<A>
    }
}

Upvotes: 1

Sergey Berezovskiy
Sergey Berezovskiy

Reputation: 236228

There is no such type of constraints in .NET. There is only six types of constraints available (see Constraints on Type Parameters):

  • where T: struct type argument must be a value type
  • where T: class type argument must be a reference type
  • where T: new() type argument must have a public parameterless constructor
  • where T: <base class name> type argument must be or derive from the specified base class
  • where T: <interface name> type argument must be or implement the specified interface
  • where T: U type argument supplied for T must be or derive from the argument supplied for U

If you want to cast string to your type, you can do casting to object first. But you can't put constraint on type parameter to make sure this casting can occur:

static T GetObjectFromRegistry<T>(string regPath)
{
    string regValue = //Getting the regisstry value...
    T objectValue = (T)(object)regValue;
    return objectValue ;
}

Another option - create interface:

public interface IInitializable
{
    void InitFrom(string s);
}

And put it as constraint:

static T GetObjectFromRegistry<T>(string regPath) 
  where T: IInitializable, new()
{
    string regValue = //Getting the regisstry value...   
    T objectValue = new T();
    objectValue.InitFrom(regValue);
    return objectValue ;
}

Upvotes: 9

Alex
Alex

Reputation: 23300

Constraints spell out like "the type of T must either be of type U or inherit type U", so the constraint you are looking for isn't doable.

everything is "castable" to String anyway, through .ToString() (YMMV)

Upvotes: 0

om471987
om471987

Reputation: 5627

Types are determined during compilation. You can't change the types during runtime. It is possible to cast object to its base or child class

Ref -

Difference between object a = new Dog() vs Dog a = new Dog()

Upvotes: 0

Related Questions