2015-04-28 52 views
1

我一直致力於使用Faker.NET來生成假數據庫。我遇到的問題是我不知道如何訪問我傳遞給我的子類的構造函數的匿名方法。如何從通用列表訪問匿名方法?

的問題是,爲了創造泛型列表我要創建基類DataGenerator但我不能拉我Func<T>成員,因爲基類是不通用的,所以沒有T可用。然而,我的DataGenerator<T>類確實暴露了我的匿名方法的Generator屬性,但是在迭代我的數據生成器列表時,我還沒有找到訪問它的方法。

任何意見將不勝感激。

這是我到目前爲止有:

public class Employee 
{ 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public Guid EmpUid { get; set; } 
} 

// Define other methods and classes here 
public abstract class DataGenerator 
{ 
    public abstract int GetWeight(string matchingProperty); 
    public abstract Type Type { get;} 
} 

public abstract class DataGenerator<T> : DataGenerator 
{ 
    public readonly string[] Tags; 
    public readonly Func<T> Generator; 
    protected DataGenerator(Func<T> generator, params string[] tags) 
    { 
     Tags = tags; 
     //How to access this? 
     Generator = generator; 
    } 

    public override int GetWeight(string matchingProperty) 
    { 
     int sum = (from tag in Tags 
      where matchingProperty.ToLowerInvariant().Contains(tag.ToLowerInvariant()) 
      select 1).Sum(); 
     return sum; 
    } 

    public override Type Type { 
     get { return typeof(T); } 
    } 
} 

public class StringDataGenerator : DataGenerator<string> 
{ 
    public StringDataGenerator(Func<string> generator, params string[] tags) : base(generator, tags) 
    { 
    } 
} 

public class GuidDataGenerator : DataGenerator<Guid> 
{ 
    public GuidDataGenerator(Func<Guid> generator, params string[] tags) 
     : base(generator, tags) 
    { 
    } 
} 

而且我在這裏測試它:

private static void Main(string[] args) 
    { 
     var dataGeneratorList = new List<DataGenerator> 
     { 
      new StringDataGenerator(Name.First, "first", "name"), 
      new StringDataGenerator(Name.Last, "last", "name"), 
      new GuidDataGenerator(Guid.NewGuid, "uid", "id") 
     }; 

     var writeProperties = typeof (Employee).GetProperties().Where(p => p.CanWrite); 
     foreach (var property in writeProperties) 
     { 
      foreach (var dataGenerator in dataGeneratorList) 
      { 
       if (property.PropertyType == dataGenerator.Type) 
       { 
        var weigth = dataGenerator.GetWeight(property.Name); 
        //How to access generator here??? 
        var testValue = dataGenerator.Generator.Invoke(); 
       } 
      } 
     } 
    } 
+2

爲什麼不添加具有過載'在你的基類object'爲抽象與強制轉換爲'T'實現它? –

+0

我想我早些時候嘗試過@AndreasNiedermair,但由於某種原因,我無法使它工作 –

+0

在基類中添加抽象'object'重載的原因不起作用的是,在我的情況下,Guid.NewGuid返回Guid這不是一個對象,而是一個'struct',它不會從'System.Object'繼承, –

回答

1

當你標記,鑑於你目前的設置,反射可能是你唯一的選擇。

var func = dataGenerator.GetType().GetField("Generator").GetValue(dataGenerator); 
var testValue = func.GetType().GetMethod("Invoke").Invoke(func, null); 

我不知道任何人都可以稱之爲超級漂亮,而且它不會是超級快,但它可能是任何東西,你需要在假數據足夠了,我想。

好的措施,here's it in action


你的問題實際上比面值更復雜一點。處理這個,如果你永遠只能用它object形式的一個很好的方式就是一個抽象Generate方法添加到基地,非通用類:

public abstract object Generate(); 

然後在重寫它的通用之一:

public override object Generate() 
{ 
    return this.Generator(); 
} 

當然,這將返回一個object,這在泛型類中並不好。但至少它避免了反思。

另一種避免這種反射無意義的方法可能是使用協方差,但不幸的是,break for value types, like Guid

public interface IDataGenerator<out T> 
{ 
    int GetWeight(string matchingProperty); 
    Type Type { get;} 
    T Generate(); 
} 

public abstract class DataGenerator<T> : IDataGenerator<T> 
{ 
    public readonly string[] Tags; 
    public readonly Func<T> Generator; 
    protected DataGenerator(Func<T> generator, params string[] tags) 
    { 
     Tags = tags; 
     //How to access this? 
     Generator = generator; 
    } 

    public T Generate(){ 
     return this.Generator(); 
    } 

    . . . 
} 

這則變成最好,

private static void Main(string[] args) 
{ 
    var dataGeneratorList = new List<IDataGenerator<object>> 
    { 
     new StringDataGenerator(Name.First, "first", "name"), 
     new StringDataGenerator(Name.Last, "last", "name") 

//   But this line doesn't work 
//   new GuidDataGenerator(Guid.NewGuid, "uid", "id") 
    }; 

    var writeProperties = typeof (Employee).GetProperties().Where(p => p.CanWrite); 
    foreach (var property in writeProperties) 
    { 
     foreach (var dataGenerator in dataGeneratorList) 
     { 
      if (property.PropertyType == dataGenerator.Type) 
      { 
       var weigth = dataGenerator.GetWeight(property.Name); 

       var testValue = dataGenerator.Generate(); 
      } 
     } 
    } 
} 
+0

謝謝@MathewHaugen。有趣的解決方案。我認爲你也得出了Guids讓我擺脫優雅解決方案的結論。到目前爲止,反思技巧似乎在做這項工作。我會等待看看有沒有更多的建議。 –

+1

@AdolfoPerez Guids只是使用協方差時的一個問題。對於第二種方法,它們工作得很好,使用返回'object'的方法。我唯一的問題在於原則上,當我真正知道它會是什麼類型時('T'),它會感覺髒並返回一個「對象」。但它的工作。 –

+0

我認爲你的第二個選擇是最適合我需要的。標記爲已回答。謝謝你的幫助! –