Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/258.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#_.net_Custom Attributes - Fatal编程技术网

数据类型的c#自定义属性

数据类型的c#自定义属性,c#,.net,custom-attributes,C#,.net,Custom Attributes,我正在考虑创建一个自定义属性,以便在不同的对象/表上使用多个数据读取器[SqldataReader]时,可以使用该属性获取属性的类型以及属性的“columnName”。这样,我们就可以有一个方法,将数据读取器作为参数,并从中反映要在列中读取的属性。下面是目前正在做的一个例子,然后是我正在努力完成的一个例子。我的问题是,如何管理,如何告诉它(类型)是什么 我的想法是,如果我有一个这样的班级: [DataReaderHelper("MethodNameToGetType", "ColumnName"

我正在考虑创建一个自定义属性,以便在不同的对象/表上使用多个数据读取器[
SqldataReader
]时,可以使用该属性获取属性的类型以及属性的“
columnName
”。这样,我们就可以有一个方法,将数据读取器作为
参数
,并从中反映要在列中读取的属性。下面是目前正在做的一个例子,然后是我正在努力完成的一个例子。我的问题是,如何管理,如何告诉它(类型)是什么

我的想法是,如果我有一个这样的班级:

[DataReaderHelper("MethodNameToGetType", "ColumnName")]
public string APPNAME {get;set;}

我该怎么做呢

首先,这是可能的,如果您愿意,我可以添加一个代码示例。 但是:这不是一个好主意

为什么,你问

首先-DataReader为您提供了一个GetSchemaTable()方法,该方法包含一个属性
DataType
,它是一个
System.Type
对象。因此,基本上您可以创建一个
mccdbulity.GetValue(dr,“columnName”)
来为您的应用程序执行逻辑

第二,如果对象上有一个int属性,但datareader返回一个小数,那该怎么办。对于这种情况,您可以使用
Convert.ChangeType(值,类型)

如果你把这些结合起来,你就可以实现你想要的

instance.Id = MCCDBUtility.GetValue<int>(dr, "columnName")

public T GetValue<T>(IDataReader reader, string columnName)
{
     object value GetValue(reader, columnName);
     return Convert.ChangeType(value, typeof(T));
}

private object GetValue(IDataReader reader, string columnName)
{
    var schmema = reader.GetSchemaTable();
    var dbType = typeof(object);
    foreach(DataRowView row in schema.DefaultView)
        if (row["columnName"].ToString().Equals(columnName, StringComparer.OrdinalIgnoreCase))
            return row["ColumnType"];

    if (dbType.Equals(typeof(int))
        return GetInt(reader, columnName)
    ... // you get the point
    else
        return GetObject(reader, columnName);
}

您是否在询问如何将APPNAME作为字符串获取?通常情况下,您只需要使用类似ORM的实体框架或Dapper来进行这种映射。也许我不太了解您的目标的全部范围,但在我看来,实体框架中捕获了一些(或至少是其中的一部分)。你有没有考虑过这种可能性?这可能会阻止你重新发明轮子:)只是一个想法。这是一个已解决的问题,在这种情况下我真的推荐。你正在寻找一个ORM。正如@DavidW所说的,退房或者。谢谢,听起来不错。我想要做的一件事是,也不必输入列名。因此,属性必须是列名,甚至反映属性名,并使其与列名匹配。不过,我明白你的意思,也很感谢你的反馈。@Casey如我所承诺的那样,我添加了一个完整功能的单元测试,演示了如何做到这一点,但它使用了反射,因此与Dapper或Entity Framework相比,我不会太快。
instance.Id = MCCDBUtility.GetValue<int>(dr, "columnName")

public T GetValue<T>(IDataReader reader, string columnName)
{
     object value GetValue(reader, columnName);
     return Convert.ChangeType(value, typeof(T));
}

private object GetValue(IDataReader reader, string columnName)
{
    var schmema = reader.GetSchemaTable();
    var dbType = typeof(object);
    foreach(DataRowView row in schema.DefaultView)
        if (row["columnName"].ToString().Equals(columnName, StringComparer.OrdinalIgnoreCase))
            return row["ColumnType"];

    if (dbType.Equals(typeof(int))
        return GetInt(reader, columnName)
    ... // you get the point
    else
        return GetObject(reader, columnName);
}
[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void TestMethod1()
    {
        var values = new Dictionary<string, object>();
        values.Add("ProductId", 17);
        values.Add("ProductName", "Something");
        values.Add("Price", 29.99M);

        var reader = new FakeDataReader(values);

        var product1 = new Product();
        reader.SetValue(product1, p => p.Id);
        reader.SetValue(product1, p => p.Name);
        reader.SetValue(product1, p => p.Price);

        Assert.AreEqual(17, product1.Id);
        Assert.AreEqual("Something", product1.Name);
        Assert.AreEqual(29.99M, product1.Price);

        var product2 = new Product();
        reader.SetAllValues(product2);

        Assert.AreEqual(17, product2.Id);
        Assert.AreEqual("Something", product2.Name);
        Assert.AreEqual(29.99M, product2.Price);
    }

}

public class Product
{
    [Mapping("ProductId")]
    public int Id { get; set; }

    [Mapping("ProductName")]
    public string Name { get; set; }

    public decimal Price { get; set; }
}

[AttributeUsage(AttributeTargets.Property, AllowMultiple=false)]
public class MappingAttribute : Attribute
{
    public MappingAttribute(string columnName)
    {
        this.ColumnName = columnName;
    }

    public string ColumnName { get; private set; }
}

public static class IDataReaderExtensions
{
    public static void SetAllValues(this IDataReader reader, object source)
    {
        foreach (var prop in source.GetType().GetProperties())
        {
            SetValue(reader, source, prop);
        }
    }
    public static void SetValue<T, P>(this IDataReader reader, T source, Expression<Func<T, P>> pe)
    {
        var property = (PropertyInfo)((MemberExpression)pe.Body).Member;
        SetValue(reader, source, property);
    }

    private static void SetValue(IDataReader reader, object source, PropertyInfo property)
    {
        string propertyName = property.Name;
        var columnName = propertyName;
        var mapping = property.GetAttribute<MappingAttribute>();
        if (mapping != null) columnName = mapping.ColumnName;

        var value = reader.GetValue(reader.GetOrdinal(columnName));
        var value2 = Convert.ChangeType(value, property.PropertyType);
        property.SetValue(source, value2, null);
    }
}

public static class ICustomFormatProviderExtensions
{
    public static T GetAttribute<T>(this ICustomAttributeProvider provider)
    {
        return (T)provider.GetCustomAttributes(typeof(T), true).FirstOrDefault();
    }
}

public class FakeDataReader : IDataReader
{
    private Dictionary<string, object> values;

    public FakeDataReader(Dictionary<string, object> values)
    {
        this.values = values;
    }

    public int GetOrdinal(string name)
    {
        int i = 0;
        foreach (var key in values.Keys)
        {
            if (key.Equals(name, StringComparison.OrdinalIgnoreCase)) return i;
            i++;
        }
        return -1;
    }

    public object GetValue(int i)
    {
        return values.Values.ToArray()[i];
    }
}