C# 如何从泛型列表访问匿名方法?

C# 如何从泛型列表访问匿名方法?,c#,generics,reflection,C#,Generics,Reflection,我一直在研究一个库,用它来生成假数据。我遇到的问题是,我不知道如何访问传递给DataGenerator子类构造函数的匿名方法 问题是为了创建泛型列表,我必须创建基类DataGenerator,但我不能向上拉我的Func成员,因为基类不是泛型的,所以没有可用的T。然而,我的DataGenerator类确实公开了Generator属性,这是我的匿名方法,但在迭代我的数据生成器列表时,我还没有找到访问它的方法 如有任何建议,将不胜感激 这就是我到目前为止所做的: public class Employ

我一直在研究一个库,用它来生成假数据。我遇到的问题是,我不知道如何访问传递给
DataGenerator
子类构造函数的匿名方法

问题是为了创建泛型列表,我必须创建基类
DataGenerator
,但我不能向上拉我的
Func
成员,因为基类不是泛型的,所以没有可用的
T
。然而,我的
DataGenerator
类确实公开了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)
    {
    }
}
公共类员工
{
公共字符串名{get;set;}
公共字符串LastName{get;set;}
公共Guid EmpUid{get;set;}
}
//在此处定义其他方法和类
公共抽象类数据生成器
{
公共抽象int GetWeight(字符串匹配属性);
公共抽象类型{get;}
}
公共抽象类DataGenerator:DataGenerator
{
公共只读字符串[]标记;
公共只读函数生成器;
受保护的数据生成器(Func生成器,参数字符串[]标记)
{
标签=标签;
//如何访问这个?
发电机=发电机;
}
public override int GetWeight(字符串匹配属性)
{
int sum=(来自标记中的标记
其中matchingProperty.ToLowerInvariant()包含(tag.ToLowerInvariant())
选择1.Sum();
回报金额;
}
公共重写类型{
获取{return typeof(T);}
}
}
公共类StringDataGenerator:DataGenerator
{
公共StringDataGenerator(Func生成器,参数字符串[]标记):基(生成器,标记)
{
}
}
公共类GuidDataGenerator:数据生成器
{
公共GuidDataGenerator(Func生成器,参数字符串[]标记)
:底座(发电机、标签)
{
}
}
我在这里测试它:

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();
                }
            }
        }
    }
private static void Main(字符串[]args)
{
var dataGeneratorList=新列表
{
新StringDataGenerator(Name.First,“First”,“Name”),
新StringDataGenerator(Name.Last,“Last”,“Name”),
新的GuidDataGenerator(Guid.NewGuid,“uid”,“id”)
};
var writeProperties=typeof(Employee).GetProperties(),其中(p=>p.CanWrite);
foreach(writeProperties中的var属性)
{
foreach(dataGeneratorList中的var dataGenerator)
{
if(property.PropertyType==dataGenerator.Type)
{
var weigth=dataGenerator.GetWeight(property.Name);
//如何在这里访问发电机???
var testValue=dataGenerator.Generator.Invoke();
}
}
}
}

在标记时,考虑到当前设置,反射可能是您唯一的选择

var func = dataGenerator.GetType().GetField("Generator").GetValue(dataGenerator);
var testValue = func.GetType().GetMethod("Invoke").Invoke(func, null);
我不确定是否有人能称之为“超级好”,它也不会非常快,但我想它可能足以满足任何需要虚假数据的需求

好的措施


你的问题实际上比表面上看起来要复杂一些。如果只在
对象
表单中使用它,那么处理这个问题的一个好方法就是向基本的非泛型类添加一个抽象的
生成
方法:

public abstract object Generate();
然后在您的通用版本中覆盖它:

public override object Generate()
{
    return this.Generator();
}
当然,这将返回一个
对象
,这在泛型类中是不好的。但至少它避免了反思

另一个避免这种反射胡说八道的解决方案可能是使用协方差,尽管不幸的是,协方差会

公共接口IDataGenerator
{
int GetWeight(字符串匹配属性);
类型{get;}
T生成();
}
公共抽象类数据生成器:IDataGenerator
{
公共只读字符串[]标记;
公共只读函数生成器;
受保护的数据生成器(Func生成器,参数字符串[]标记)
{
标签=标签;
//如何访问这个?
发电机=发电机;
}
公共T生成(){
返回此.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();
            }
        }
    }
}
private static void Main(字符串[]args)
{
var dataGeneratorList=新列表
{
新StringDataGenerator(Name.First,“First”,“Name”),
新的StringDataGenerator(Name.Last,“Last”,“Name”)
//但是这条线不行
//新的GuidDataGenerator(Guid.NewGuid,“uid”,“id”)
};
var writeProperties=typeof(Employee).GetProperties(),其中(p=>p.CanWrite);
foreach(writeProperties中的var属性)
{
foreach(dataGeneratorList中的var dataGenerator)
{
if(property.PropertyType==dataGenerator.Type)
{
var weigth=dataGenerator.GetWeight(property.Name);
var testValue=dataGenerator.Generate();
}
}
}
}

为什么不在基类中将
对象作为抽象添加一个重载,并通过转换为
T
来实现它呢?我想我之前曾尝试过@AndreasNiedermair,但由于某些原因我无法使其工作在基类中添加抽象
对象
重载的原因是在我的例子中Guid.NewGuid不起作用返回一个不是对象而是结构的Guid,它不是从
系统继承的。对象
,但是有一个可以拯救你的拳击…谢谢@MathewHaugen。有趣的解决方案。我想你也得出了这样的结论:guid让我无法想出一个优雅的解决方案。到目前为止,反射技巧似乎正在发挥作用。我会等待,看看是否有更多的建议。@AdolfoPerez GUI只是使用协方差时的一个问题。对于第二种方法,它们工作得很好,方法返回
object
。我唯一的
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();
            }
        }
    }
}