I am trying to create an instance of a class using factory builder from the parent.
The use case is basically a library that contains series of classes that inherit from the same class. The main goal was to reduce the amount of code in those classes.
I have an interface that contains two values, IDualValues<T>
.
public interface IDualValues<T>
{
public T FirstValue { get; }
public T SecondValue { get; }
}
This is an example of what all the classes will look like (changing the method name).
public class Foo : IDualValues<string>
{
public string FirstValue { get; }
public string SecondValue { get; }
public Foo(string firstValue, string secondValue)
{
FirstValue = firstValue;
SecondValue = secondValue;
}
public static Foo Create(string firstValue, string secondValue)
{
return new Foo(firstValue, secondValue);
}
}
My point is that I want to use the FactoryBuilder to do Foo.Create
instead of a new instance directly in the client application.
The ideal scenario will have a parent class that contains all the logic:
public class DualValuesBuilder<T, CreatedType> : IDualValues<T>
where CreatedType : class, IDualValues<T>
{
public T FirstValue { get; init; }
public T SecondValue { get; init; }
private DualValuesBuilder(T firstValue, T secondValue)
{
FirstValue = firstValue;
SecondValue = secondValue;
}
public static CreatedType Create(T firstValue, T secondValue)
{
//Creation here
}
}
and the other classes will be empty classes just implementing that one:
public class Foo : DualValuesBuilder<string, Foo>
{
}
Notice that I am sending the class itself as a generic parameter to the "builder".
To Achieve my goal, I created a "helper" class to build a class that inherits from IDualValues<T>
.
public class DualValuesBuilderHelper<T> : IDualValues<T>
{
public T FirstValue { get; init;}
public T SecondValue { get; init; }
private DualValuesBuilderHelper(T firstValue, T secondValue)
{
FirstValue = firstValue;
SecondValue = secondValue;
}
public static IDualValues<T> Create<ReturnType>(T developerK8SClusterValue, T octopusValue)
where ReturnType : IDualValues<T>
{
return new DualValuesBuilderHelper<T>(developerK8SClusterValue, octopusValue);
}
}
and then I updated the Create
method in the class DualValuesBuilder
to look like the next:
public static CreatedType Create(T firstValue, T secondValue)
{
return (CreatedType)DualValuesBuilderHelper<T>.Create<CreatedType>(firstValue, secondValue);
}
But that is giving me an error on the casting:
System.InvalidCastException: Unable to cast object of type 'DualValuesBuilderHelper
1[System.String]' to type 'Foo'.`
Here there is a fiddle with the code: https://dotnetfiddle.net/IUrgr1
Yes, if I do the following works, but is not what I am trying to achieve.
Foo foo = new Foo()
{
FirstValue = "f1",
SecondValue = "f2"
};
note: Using the construtor also works, but I need to make it work with the Create
.
Even if I create an explicit (or implicit) operator, the casting still happening.
Am I overthinking, and there is a simple way of accomplishing what I am trying to do? Or is it not possible to do?
Thanks.
Updated as I'd missed the nuance of the inherited factory method.
Primarily adding new()
to the generic constraint will sort you out, and including CreateType
must be a child of DualValuesBuilder
: where CreateType : DualValuesBuilder<CreateType, DataType>, new()
public interface IDualValues<T>
{
public T FirstValue { get; init; }
public T SecondValue { get; init; }
}
public class Foo : DualValuesBuilder<Foo, string>
{
}
public class Foo2 : DualValuesBuilder<Foo2, int>
{
}
public class DualValuesBuilder<CreateType, DataType> : IDualValues<DataType>
where CreateType : DualValuesBuilder<CreateType, DataType>, new()
{
public DataType FirstValue { get; init; }
public DataType SecondValue { get; init; }
public static CreateType Create(DataType firstValue, DataType secondValue)
{
return new CreateType
{
FirstValue = firstValue,
SecondValue = secondValue
};
}
}
Primarily adding new()
to the generic constraint will sort you out: where CreatedType : class, IDualValues<T>, new()
public interface IDualValues<T>
{
public T FirstValue { get; init; }
public T SecondValue { get; init; }
}
public class Foo : IDualValues<string>
{
public string FirstValue { get; init; }
public string SecondValue { get; init; }
}
public static class DualValuesBuilder
{
public static CreateType Create<CreateType, DataType>(
DataType firstValue,
DataType secondValue)
where CreateType : class, IDualValues<DataType>, new()
{
return new CreateType
{
FirstValue = firstValue,
SecondValue = secondValue
};
}
}