2016-02-26 47 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