2016-02-26 81 views
3

有什么办法可以将的Parse方法移入抽象类?我尝试了多种方式(链接在底部),但我仍然遇到了一个或另一个障碍。约束参数,新建()

public class AnimalEntityId : EntityId<AnimalEntityId> 
{ 
    public AnimalEntityId() 
     : base() 
    { 
    } 

    private AnimalEntityId(string value) 
     : base(value) 
    { 
    } 

    public static AnimalEntityId Parse(string value) 
    { 
     return new AnimalEntityId(value); 
    } 
} 


public abstract class EntityId<TEntityId> 
{ 
    private readonly System.Guid value; 

    protected EntityId(string value) 
    { 
     this.value = System.Guid.Parse(value); 
    } 

    protected EntityId() 
    { 
     this.value = System.Guid.NewGuid(); 
    } 
} 

尝试了这些建议,没有运气:

在此先感谢!

+0

澄清:你正在寻找一个方法'公共静态TEntityId解析(字符串值){...}'在抽象类?该方法是否是'EntityId <>'抽象的唯一原因?因为我没有真正看到它是通用*和*抽象的原因,至少在这个简化的例子中。 –

回答

1

子类。如果你不介意使用反射,你可以移动到Parse抽象类型是这样的:

public static TEntityId Parse(string val) { 
    var constr = typeof(TEntityId).GetConstructor(
     // Since the constructor is private, you need binding flags 
     BindingFlags.Instance | BindingFlags.NonPublic 
    , null 
    , new[]{ typeof(string) } 
    , null); 
    if (constr == null) { 
     throw new InvalidOperationException("No constructor"); 
    } 
    return (TEntityId)constr.Invoke(new object[] {val}); 
} 

Demo.

1

不,你不能写一个模板约束,如new(string)而不是简单的new()。你必须利用反射来得到它的工作:

public abstract class EntityId<TEntityId> 
    where TEntityId : EntityId<TEntityId> 
{ 
    private readonly System.Guid value; 

    protected EntityId(string value) 
    { 
     this.value = System.Guid.Parse(value); 
    } 

    protected EntityId() 
    { 
     this.value = System.Guid.NewGuid(); 
    } 

    public static TEntityId Parse(string value) 
    { 
     return (TEntityId)Activator.CreateInstance(typeof(TEntityId), new object[] { value }); 
    } 
} 

假设你可以构造(而不是它目前正在私人)访问。注意约束where TEntityId : EntityId<TEntityId> - 这将确保我们只返回的EntityId

+1

谢谢Rob,非常干净的解决方案。因为我不会在循环中创建数百个对象,所以在思考了一会儿之后,我决定按照你的建议去反思,因为这样我可以为其他开发者(或者在几个月之后)提供最易读的API ),谁将使用这个类库。拥有简单的AnimalEntityId.Parse(“ID”)对我来说是一个巨大的优点。我还开始添加更改以访问非公共构造函数,并且意识到,我拥有与@dasblinkenlight – Zygimantas

1

如何使value是一个私人可变字段/属性并实际从Parse方法中设置它?

(从EntityId除去简单奇怪的是反复出现的泛型参数)

public class SimpleAnimalEntityId : EntityId 
{ 
    // Implicit parameterless constructor. 
} 

public class ParametrizedAnimalEntityId : EntityId 
{ 
    // Parametrized constructor only. 
    public ParametrizedAnimalEntityId(int ignored) 
    { 
    } 
} 

public abstract class EntityId 
{ 
    // Simple scenario: derived type has a parameterless constructor. 
    public static TEntity Parse<TEntity>(string value) 
     where TEntity : EntityId, new() 
    { 
     Guid id = Guid.Parse(value); 

     return new TEntity { value = id }; 
    } 

    // Advanced scenario: derived type constructor needs parameters injected. 
    public static TEntity Parse<TEntity>(string value, Func<TEntity> constructor) 
     where TEntity : EntityId 
    { 
     Guid id = Guid.Parse(value); 
     TEntity entity = constructor(); 

     entity.value = id; 

     return entity; 
    } 

    private Guid value; 

    protected EntityId() 
    { 
     value = Guid.NewGuid(); 
    } 
} 

现在你可以从你的Parse方法处理任何构造函数:

string id = Guid.NewGuid().ToString(); 
SimpleAnimalEntityId simple = EntityId.Parse<SimpleAnimalEntityId>(id); 
ParametrizedAnimalEntityId parametrized = EntityId.Parse(id,() => new ParametrizedAnimalEntityId(42)); 
+0

Kirill建议的代码相同的代码,谢谢,非常有趣的方法。我决定在这种情况下使用反射,因为在这种情况下,我可以保持API更清洁:AnimalEntityId.Parse(“ID”),而不是EntityId.Parse (id)。在你的建议中,我觉得实现细节不应该对用户看得太清楚。 – Zygimantas