如何从通用列表中访问匿名方法?

时间:2015-04-28 22:08:56

标签: c# generics reflection

我一直在使用Faker.NET来创建虚假数据库。我遇到的问题是,我不知道如何访问我传递给DataGenerator子类的构造函数的匿名方法。

问题在于,为了创建泛型列表,我必须创建基类DataGenerator,但我不能拉我的Func<T>成员,因为该基类不是通用的,所以没有{{1 }}可用。但是,我的T类确实公开了Generator属性,这是我的匿名方法,但在迭代我的数据生成器列表时,我还没有找到访问它的方法。

任何建议都将受到高度赞赏。

这是我到目前为止所做的:

DataGenerator<T>

我在这里测试它:

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)
    {
    }
}

1 个答案:

答案 0 :(得分: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();
            }
        }
    }
}