无法解析符号以用作泛型类型参数

时间:2014-02-11 21:53:41

标签: c# generics reflection

我正在尝试从通过反射找到的Type创建一个类的新实例。当调用TableInsert()时,'destType'无法解析,当用作方法的参数时,我收到此错误:“参数类型'System.Type'不能赋值给参数类型'destType。'”我有一种感觉回答这个问题非常简单,我只是盯着代码太久了。

//this is executed first
private void ImportData(IDataMapping tableMap)
{
    //destType is a class of POCOs that match column names from a database table
    //the class inherits from a base class called SchemaObject which inherits from ISchemaObject which itself inherits from INotifyPropertyChanged
    //an example name would be 'SchemaEmployees' where employees is the destination table name
    Type destType = typeof(ISchemaObject).Assembly.GetTypes()
                    .FirstOrDefault(t => t.Name.ToLower() == "schema" + tableMap.tableName.ToLower());

    if (destType == null)
        throw new NullReferenceException("Could not find class mapping for table " + tableMap.tableName + ".");

    //the list of public properties on the POCO class, i.e. the columns from the database table
    List<PropertyInfo> destProps = destType.GetProperties().ToList();

    //here I create a DataSet from a DataAdapter for the destination insert table 
    //here I get a DbDataReader from a source database and run ExecuteReader()
    using (DataSet ds = GetTableDs())
    using (DbDataReader reader = GetSourceData())
        while (reader.Read())
        {
            TableInsert<destType>(tableMap, reader, ds, destType, destProps);
        }
}  

//this is where the DataRow for the destination database is created and the columns mapped to the class POCOs
private void TableInsert<T>(
    IDataMapping tableMap,
    DbDataReader r, //source
    DataSet ds, //destination
    T destClassType,
    IList<PropertyInfo> destClassProperties) 
    where T : ISchemaObject
{
    var dr = ds.Tables[0].NewRow();

    var dest = dr.CreateItemFromRow<destClassType>(destClassProperties) as ISchemaObject;

    //sets the DataRow column value when the class property value changes
    dest.PropertyChanged += (sender, eArgs) =>
    {
        dr[eArgs.PropertyName] =
            destClassType
            .GetType()
            .GetProperty(eArgs.PropertyName, BindingFlags.Public | BindingFlags.Instance)
            .GetValue(sender, null);
    };

    //the source DataReader row is converted to a Dynamic class
    //it's not type safe, but the source changes frequently so properly mapping it would add undue complexity to the project        
    var srcEnt = new DynamicEntityGenerator.DataReaderEntity(r);

    dynamic dynSrc = srcEnt;

    //in this method the destination class (bound to the DataRow that will be inserted) properties are mapped to the source Dynamic class's properties
    tableMap.MapInsertClasses<ISchemaObject>(dynSrc, dest);

    ds.Tables[0].Rows.Add(dr);
}  

//DataRow extension method for mapping the row to a class containing properties with the same name as the DataColumn names
public static T CreateItemFromRow<T>(
    this DataRow row,
    IList<PropertyInfo> properties)
    where T : new()
{
    T item = new T();

    foreach (var property in properties)
    {
        if (row[property.Name] != DBNull.Value)
            property.SetValue(item, row[property.Name], null);
    }

    return item;
}  

1 个答案:

答案 0 :(得分:0)

你不能以这种方式使用泛型,但实际上你并不需要它。你可以这样做:

//this is executed first
private void ImportData(IDataMapping tableMap)
{
    //destType is a class of POCOs that match column names from a database table
    //the class inherits from a base class called SchemaObject which inherits from ISchemaObject which itself inherits from INotifyPropertyChanged
    //an example name would be 'SchemaEmployees' where employees is the destination table name
    Type destType = typeof(ISchemaObject).Assembly.GetTypes()
                    .FirstOrDefault(t => t.Name.ToLower() == "schema" + tableMap.tableName.ToLower());

    if (destType == null)
        throw new NullReferenceException("Could not find class mapping for table " + tableMap.tableName + ".");

    //the list of public properties on the POCO class, i.e. the columns from the database table
    List<PropertyInfo> destProps = destType.GetProperties().ToList();

    //here I create a DataSet from a DataAdapter for the destination insert table 
    //here I get a DbDataReader from a source database and run ExecuteReader()
    using (DataSet ds = GetTableDs())
    using (DbDataReader reader = GetSourceData())
        while (reader.Read())
        {
            TableInsert(tableMap, reader, ds, destType, destProps);
        }
}  

//this is where the DataRow for the destination database is created and the columns mapped to the class POCOs
private void TableInsert(
    IDataMapping tableMap,
    DbDataReader r, //source
    DataSet ds, //destination
    Type destClassType,
    IList<PropertyInfo> destClassProperties)
{
    var dr = ds.Tables[0].NewRow();

    var dest = dr.CreateItemFromRow(destClassType, destClassProperties) as ISchemaObject;

    //sets the DataRow column value when the class property value changes
    dest.PropertyChanged += (sender, eArgs) =>
    {
        dr[eArgs.PropertyName] =
            destClassType
            .GetType()
            .GetProperty(eArgs.PropertyName, BindingFlags.Public | BindingFlags.Instance)
            .GetValue(sender, null);
    };

    //the source DataReader row is converted to a Dynamic class
    //it's not type safe, but the source changes frequently so properly mapping it would add undue complexity to the project        
    var srcEnt = new DynamicEntityGenerator.DataReaderEntity(r);

    dynamic dynSrc = srcEnt;

    //in this method the destination class (bound to the DataRow that will be inserted) properties are mapped to the source Dynamic class's properties
    tableMap.MapInsertClasses<ISchemaObject>(dynSrc, dest);

    ds.Tables[0].Rows.Add(dr);
}  

//DataRow extension method for mapping the row to a class containing properties with the same name as the DataColumn names
public static ISchemaObject CreateItemFromRow(
    this DataRow row,
    Type type,
    IList<PropertyInfo> properties)
{
    var item = (ISchemaObject)Activator.CreateInstance(type);

    foreach (var property in properties)
    {
        if (row[property.Name] != DBNull.Value)
            property.SetValue(item, row[property.Name], null);
    }

    return item;
}  

如果需要,您还可以验证该类型实际上是ISchemaObject并且具有无参数构造函数。