如何从通用列表访问匿名方法?
How to access anonymous method from generic list?
我一直在开发一个使用 Faker.NET 生成假数据的库。我遇到的问题是我不知道如何访问我传递给 DataGenerator
子 classes.
的构造函数的匿名方法
问题是,为了创建泛型列表,我必须创建基础 class DataGenerator
但我无法拉起我的 Func<T>
成员,因为该基础 class 不是通用的,因此没有 T
可用。但是,我的 DataGenerator<T>
class 确实公开了生成器 属性 这是我的匿名方法,但我在迭代数据生成器列表时没有找到访问它的方法。
任何建议将不胜感激。
这是我目前拥有的:
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();
}
}
}
}
正如您标记的那样,鉴于您当前的设置,反射可能是您唯一的选择。
var func = dataGenerator.GetType().GetField("Generator").GetValue(dataGenerator);
var testValue = func.GetType().GetMethod("Invoke").Invoke(func, null);
我不确定有人会说这超级好,而且它不会超级快,但我想它可能足以满足您需要伪造数据的任何事情。
为了更好的衡量,here's it in action。
您的问题实际上比表面上看起来要复杂一些。如果你只在 object
形式中使用它,一个很好的处理方法是将抽象 Generate
方法添加到基本的非泛型 class:
public abstract object Generate();
然后在您的通用版本中覆盖它:
public override object Generate()
{
return this.Generator();
}
当然,这个 return 一个 object
,这在通用 class 中并不好。但至少它避免了反射。
另一种避免这种反射废话的解决方案可能是使用协方差,尽管不幸的是,这将 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();
}
}
}
}
我一直在开发一个使用 Faker.NET 生成假数据的库。我遇到的问题是我不知道如何访问我传递给 DataGenerator
子 classes.
问题是,为了创建泛型列表,我必须创建基础 class DataGenerator
但我无法拉起我的 Func<T>
成员,因为该基础 class 不是通用的,因此没有 T
可用。但是,我的 DataGenerator<T>
class 确实公开了生成器 属性 这是我的匿名方法,但我在迭代数据生成器列表时没有找到访问它的方法。
任何建议将不胜感激。
这是我目前拥有的:
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();
}
}
}
}
正如您标记的那样,鉴于您当前的设置,反射可能是您唯一的选择。
var func = dataGenerator.GetType().GetField("Generator").GetValue(dataGenerator);
var testValue = func.GetType().GetMethod("Invoke").Invoke(func, null);
我不确定有人会说这超级好,而且它不会超级快,但我想它可能足以满足您需要伪造数据的任何事情。
为了更好的衡量,here's it in action。
您的问题实际上比表面上看起来要复杂一些。如果你只在 object
形式中使用它,一个很好的处理方法是将抽象 Generate
方法添加到基本的非泛型 class:
public abstract object Generate();
然后在您的通用版本中覆盖它:
public override object Generate()
{
return this.Generator();
}
当然,这个 return 一个 object
,这在通用 class 中并不好。但至少它避免了反射。
另一种避免这种反射废话的解决方案可能是使用协方差,尽管不幸的是,这将 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();
}
}
}
}