Hoe om 'n persoonlike kenmerk van voorwerp byvoorbeeld in C # kry
-
22-09-2019 - |
Vra
Kom ons sê ek het 'n klas met die naam Toets met een eiendom genoem titel met 'n persoonlike kenmerk:
public class Test
{
[DatabaseField("title")]
public string Title { get; set; }
}
En 'n uitbreiding metode genoem DbField. Ek wonder of kry 'n persoonlike kenmerk van 'n voorwerp byvoorbeeld is selfs moontlik in c #.
Test t = new Test();
string fieldName = t.Title.DbField();
//fieldName will equal "title", the same name passed into the attribute above
Kan dit gedoen word?
Oplossing
Hier is 'n benadering. Die uitbreiding metode werk, maar dit is nie heeltemal so maklik nie. Ek skep 'n uitdrukking en dan haal die persoonlike kenmerk.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
namespace ConsoleApplication1
{
public class DatabaseFieldAttribute : Attribute
{
public string Name { get; set; }
public DatabaseFieldAttribute(string name)
{
this.Name = name;
}
}
public static class MyClassExtensions
{
public static string DbField<T>(this T obj, Expression<Func<T, string>> value)
{
var memberExpression = value.Body as MemberExpression;
var attr = memberExpression.Member.GetCustomAttributes(typeof(DatabaseFieldAttribute), true);
return ((DatabaseFieldAttribute)attr[0]).Name;
}
}
class Program
{
static void Main(string[] args)
{
var p = new Program();
Console.WriteLine("DbField = '{0}'", p.DbField(v => v.Title));
}
[DatabaseField("title")]
public string Title { get; set; }
}
}
Ander wenke
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
Test t = new Test();
Console.WriteLine(t.FieldName("Title").FieldName<DatabaseFieldAttribute>());
Console.WriteLine(t.FieldName("Title").FieldIsPrimaryKey<DatabaseFieldAttribute>());
}
}
public class Test
{
[DatabaseField("titlezzz", true)]
public string Title
{
get;
set;
}
}
public class BaseDatabaseFieldAttribute : Attribute
{
private readonly string _name;
public string Name { get { return _name; } }
public BaseDatabaseFieldAttribute(string name)
{
_name = name;
}
}
public class DatabaseFieldAttribute : BaseDatabaseFieldAttribute
{
private readonly bool _isPrimaryKey;
public bool IsPrimaryKey { get { return _isPrimaryKey; } }
public DatabaseFieldAttribute(string name, bool isPrimaryKey): base(name)
{
_isPrimaryKey = isPrimaryKey;
}
}
public static class Helper
{
public static PropertyInfo FieldName(this object obj, string propertyName)
{
return obj.GetType().GetProperty(propertyName);
}
public static string FieldName<T>(this PropertyInfo property) where T: BaseDatabaseFieldAttribute
{
object[] os = property.GetCustomAttributes(typeof(T), false);
if (os != null && os.Length >= 1)
return (os[0] as T).Name;
else
return "N/A";
}
public static bool? FieldIsPrimaryKey<T>(this PropertyInfo property) where T : DatabaseFieldAttribute
{
object[] os = property.GetCustomAttributes(typeof(T), false);
if (os != null && os.Length >= 1)
return (os[0] as T).IsPrimaryKey;
else
return null;
}
}
}
Dit is, maar uiteindelik is dit gaan 'n ompad wees, want jy sal die Type
byvoorbeeld van 'n beroep GetType
op jou geval dat die eiendom ontbloot werk op daardie (meer dikwels as nie) te kry, en dan.
In hierdie spesifieke geval, jou uitbreiding metode is nie van plan om in staat wees om die kenmerk inligting te kry, want al wat jy is verby om dit is 'n string.
Uiteindelik, wat jy nodig het, is iets om die PropertyInfo
kry vir die eiendom van. Ander antwoorde verwys na die Type
, wat hulle nie is, dit is nie die enigste manier om die kenmerk inligting by die PropertyInfo
wat jy wil te kry.
Jy kan dit doen deur 'n Type
byvoorbeeld met 'n string, vermoedelik, met die naam eiendom, so jy GetProperty
op die Type
kan noem.
Nog 'n manier om dit te doen sedert C # 3,0 is 'n metode wat 'n Expression<T>
neem en gebruik dan die dele van die Expression
by die PropertyInfo
te kry nie. In hierdie geval, sal jy 'n Expression<Func<string>>
of iets te neem waar TResult
is string.
As jy die PropertyInfo
, jy kan GetCustomAttributes
op dit, en kyk noem vir jou kenmerk.
Die voordeel om die uitdrukking benadering is dat Expression<T>
afgelei van LambdaExpression
, wat jy Compile
kan 'n beroep op, en dan bel om die werklike waarde kry, as jy dit nodig het.
As as al daarop gewys, is dit nie moontlik met die sintaksis van die oorspronklike plakkaat beskryf, omdat jy 'n verwysing na PropertyInfo binne die uitbreiding metode nie kan kry. Wat van iets soos hierdie:
// Extension method
public static string GetDbField(this object obj, string propertyName)
{
PropertyInfo prop = obj.GetType().GetProperty(propertyName);
object[] dbFieldAtts = prop.GetCustomAttributes(typeof(DatabaseFieldAttribute), true);
if (dbFieldAtts != null && dbFieldAtts.Length > 0)
{
return ((DatabaseFieldAttribute)dbFieldAtts[0]).Name;
}
return "UNDEFINED";
}
Jy kan dan kry die info so eenvoudig as:
Test t = new Test();
string dbField = t.GetDbField("Title");
Nee, dit is nie moontlik nie. Die rede hiervoor is dat dit die waarde en nie die eiendom self wat in enige persoonlike uitbreiding metode wat hierdie inligting sal haal sal gestuur word. Sodra jy in daardie uitbreiding metode, is daar geen betroubare manier om terug te spoor om die eiendom self.
Dit mag dalk moontlik wees vir enum waardes , maar so ver as eienskappe op POCO se dit gaan nie werk.
Met die oog op die kenmerk waarde kry, jy die tipe wat die kenmerk is van toepassing op nodig. Jou uitbreiding metode is net om 'n string waarde (die waarde van titel), sodat jy nie in staat sou wees om die werklike geval kry wat die string vandaan kom, en sodat jy kan die oorspronklike tipe nie kan kry wat die eiendom titel behoort aan. Dit maak dit onmoontlik om die kenmerk waarde van jou uitbreiding metode kry.