Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/305.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 另一个c反射_C#_Reflection - Fatal编程技术网

C# 另一个c反射

C# 另一个c反射,c#,reflection,C#,Reflection,我有一个csv文件,其中每一行都是不同类型的记录。我正在解析csv,希望将不同类型的记录存储在不同类型的自定义类中 在每一行,我需要根据记录类型实例化一个不同的类 从其他反射示例中,我得到了下面的代码 Type type = Type.GetType("myNamespace." + className); object recordclass = Activator.CreateInstance(type); 所以我有一个正确类型的名为recordclass的对象,但

我有一个csv文件,其中每一行都是不同类型的记录。我正在解析csv,希望将不同类型的记录存储在不同类型的自定义类中

在每一行,我需要根据记录类型实例化一个不同的类

从其他反射示例中,我得到了下面的代码

      Type type = Type.GetType("myNamespace." + className);
      object recordclass = Activator.CreateInstance(type);
所以我有一个正确类型的名为recordclass的对象,但如何使用它呢

我真正想做的就是访问类的属性并填充行数据,然后再添加到容器类中

我想我遗漏了一些关于反射的运行时性质的东西。请帮我把这些点连起来

希望一切都有意义

蒂亚,
Gary

如果要通过反射将值存储到recordclass的属性中,请使用以下命令

var property = type.GetProperty(propertyName);
property.SetValue(recordclass,value,null);

如果阅读文档,您将看到Type.GetType需要一个完整的限定类型名。

通过您给出的示例,您可以将对象强制转换为您需要的实际类型:

Type type = Type.GetType("myNamespace." + className);
object recordclass = Activator.CreateInstance(type);

var record = recordClass as ConcreteRecordType;
if(record != null)
    record.Name = csv["Name"];
或者,研究使用工厂返回填充的记录对象:

public class RecordFactory
{
    RecordBase ParseCsvRow(string[] columns)
    {
        const int typeDescriminatorColumn = 0;
        switch (columns[typeDescriminatorColumn])
        {
            case "RecordTypeA":
                return new RecordTypeA(columns[1], columns[2], ...);
            case "RecordTypeB":
                return new RecordTypeB(columns[1], columns[2], ...);
            default:
                throw new InvalidOperationException("Unexpected descriminator: " + columns[typeDescriminatorColumn]);
        }
    }
}

如果我理解正确,您有一个包含记录文本值的文件。每一条记录都存储在一行中,每一行的开头都是一个标识符,表示要构建哪种类型的记录

对此可以使用反射,但并非真正必要。使用反射的问题在于,您需要知道不同记录类型的所有属性,以便按名称访问它们。此时,您也可以使用类型化对象,但如果使用单个例程使用CreateInstance创建所有记录,那么您所拥有的只是一个非类型化对象

另一种解决方案是使用一组例程,如果您有一个基本记录类,并使用工厂为每一行选择要使用的例程,则每个例程都接受(例如,一个IEnumerable)以逗号分隔的输入行,不包括记录id并返回一个对象或记录

通过某个ID向工厂注册例程。记录中的第一个字段很好,它可以是记录类名称,但不必是,并遍历CSV行,使用第一个片段从工厂选择方法并构建记录

希望这个例子能更好地解释:?对不起,代码太多了

示例中的构建器只返回空记录,但从行片段填充它们应该很容易。另一个版本是只传入行,如果一条记录可以包含多行,则传入一组行;如果记录包含不同数量的行,则传入更复杂

嗯,, 艾伦


干杯,这正是我需要的。我确信我以前见过这样的代码片段,但是没有把它放在正确的上下文中,所以我轻轻松松地读了一遍。谢谢!谢谢艾伦,我正在玩弄用你的工厂理念重写的想法。再次感谢。谢谢汉斯,你的想法也值得考虑。干杯
public string[] Input = new[]{
                                    "R1, F1, F2, F3",
                                    "R2, F2, F4",
                                    "R3, F2",
                                    "R3, F2",
                                    "R4, F1, F2, F3, F4"
                                };

public class RecordOne {
}
public class RecordTwo {
}
public class RecordThree {
}
public class RecordFour {
}

public class BuilderFactory {

    public BuilderFactory() {
        Builders = new Dictionary<string, Func<IEnumerable<string>, object>>();
    }

    private Dictionary<string, Func<IEnumerable<string>, object>> Builders { get; set; }


    public void RegisterBuilder(string name, Func<IEnumerable<string>, object> builder) {
        Builders.Add(name, builder);
    }
    public Func<IEnumerable<string>, object> GetBuilder(string name) {
        return Builders[name];
    }
}


[TestMethod]
public void LoadRecords() {

    var factory = new BuilderFactory();
    factory.RegisterBuilder("R1", BuildRecordOne);
    factory.RegisterBuilder("R2", BuildRecordTwo);
    factory.RegisterBuilder("R3", BuildRecordThree);
    factory.RegisterBuilder("R4", BuildRecordFour);

    var output = Input.Select(line => {
        var pieces = line.Split(',').Select(val => val.Trim());
        var builder = factory.GetBuilder(pieces.First());
        return builder(pieces.Skip(1));
    });


    Assert.IsTrue(new[] {typeof(RecordOne),
                         typeof(RecordTwo),
                         typeof(RecordThree),
                         typeof(RecordThree),
                         typeof(RecordFour)}.SequenceEqual(output.Select(rec => rec.GetType())));

}

private static RecordOne BuildRecordOne(IEnumerable<string> pieces) {
    return new RecordOne();
}

private static RecordTwo BuildRecordTwo(IEnumerable<string> pieces) {
    return new RecordTwo();
}
private static RecordThree BuildRecordThree(IEnumerable<string> pieces) {
   return new RecordThree();
}
private static RecordFour BuildRecordFour(IEnumerable<string> pieces) {
    return new RecordFour();
}