I have an abstract class TypedIdValueBase which has subclasses like UserId or ImageId. I don't know how but I would like to have a Parse method (or a second constructor which is taking a string in parameter and not a Guid) and call it like that:
Guid valueG = Guid.NewGuid();
UserId userId1 = UserId.Parse(valueG ); //or new UserId(valueG )
ImageId imageId1 = ImageId.Parse(valueG ); // or new ImageId(valueG )
string valueS = "0f8fad5b-d9cb-469f-a165-70867728950e";
UserId userId2 = UserId.Parse(valueS ); //or new UserId(valueS )
ImageId imageId2 = ImageId.Parse(valueS ); // or new ImageId(valueS )
I would like to force each child class to have that method or a second constructor with a string parameter but I really don't know how to handle it. I know about some "simple" answers like that: Abstract Method That Returns an Instance of Derived Class
Someone already linked my previous question to another answer without reading well what I want to do. Pay attention to the type of the variables or parameters before to link and close it to an answer which is not answering the question. Thank you a lot.
The best I had was something like that:
string value = "0f8fad5b-d9cb-469f-a165-70867728950e";
UserId userId = (UserId)UserId.Parse(value); //or new TypedIdValueBase.Parse<UserId>(value)
Does anyone have an idea on how to do something like that ?
Here is the code without traces of my attempts:
public abstract class TypedIdValueBase : IEquatable<TypedIdValueBase>
{
public Guid Value { get; private set; }
protected TypedIdValueBase(Guid value)
{
if (value == Guid.Empty)
{
throw new InvalidOperationException("Id value cannot be empty!");
}
Value = value;
}
}
public class UserId : TypedIdValueBase
{
public UserId(Guid value) : base(value)
{
}
}
public class ImageId : TypedIdValueBase
{
public ImageId(Guid value) : base(value)
{
}
}
Good day,
I found a way to have something like I wanted but I'm still not sure if it's a good thing to do.
With the code below I can do:
UserId userId = UserId.Parse(stringValue);
UserId userId2 = new UserId(guidValue);
public class UserId : TypedIdValueBase<UserId>
{
public UserId(Guid value) : base(value)
{
}
}
public abstract class TypedIdValueBase<T> : TypedIdValueBase where T : TypedIdValueBase
{
public static T Parse(string value)
{
var obj = (T)new object();
obj.Value = Guid.Parse(value);
return obj;
}
protected TypedIdValueBase(Guid value) : base(value)
{
}
}
public abstract class TypedIdValueBase : IEquatable<TypedIdValueBase>
{
private Guid _value;
public Guid Value
{
get => _value;
protected internal set
{
CheckValue(value);
_value = value;
}
}
protected TypedIdValueBase(Guid value)
{
CheckValue(Value);
Value = value;
}
private void CheckValue(Guid value)
{
if (value == Guid.Empty)
{
throw new InvalidOperationException("Id value cannot be empty!");
}
}
public bool Equals(TypedIdValueBase other) => Value == other?.Value;
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
return obj is TypedIdValueBase other && Equals(other);
}
public override int GetHashCode() => Value.GetHashCode();
public static bool operator ==(TypedIdValueBase obj1, TypedIdValueBase obj2)
{
if (Equals(obj1, null))
{
if (Equals(obj2, null))
{
return true;
}
return false;
}
return obj1.Equals(obj2);
}
public static bool operator !=(TypedIdValueBase x, TypedIdValueBase y) => !(x == y);
}