Скажите, что у меня есть класс с одним свойством
Public Class MyClass
Public Property MyItem() as Object
....
End Property
End Class
Я должен передать название свойства к вызову функции. (Не спрашивайте, почему это должно быть сделано этот путь, это - сторонняя платформа). Например,
SomeFunc("MyItem")
Но то, что я хотел бы сделать, поменяйте струну в параметр со строгим контролем типов. Значение, если имя свойства переименовано или изменилось, оно должно быть отражено здесь также.
Так что-то вроде этого типа:
Dim objectForStrongTyping as New MyClass()
SomeFunc(objectForStrongTyping.MyItem().Name())
Я уверен, что это не будет работать. Существует ли способ, которым может быть сделан этот строгий контроль типов? (C# или VB.NET, любая вещь прохладна),
Вот решение, использующее классы из System.Linq.Expressions
.
static MemberInfo GetMemberInfo<TObject, TProperty>(
Expression<Func<TObject, TProperty>> expression
) {
var member = expression.Body as MemberExpression;
if (member != null) {
return member.Member;
}
throw new ArgumentException("expression");
}
Просто бросьте это где-нибудь в класс (ExpressionHelper
?).
Использование:
class SomeClass {
public string SomeProperty { get; set; }
}
MemberInfo member = GetMemberInfo((SomeClass s) => s.SomeProperty);
Console.WriteLine(member.Name); // prints "SomeProperty" on the console
Если бы можно было сделать только одно свойство - получить информацию о первом свойстве класса:
//C# syntax
typeof(MyClass).GetProperties()[0].Name;
'VB syntax
GetType(MyClass).GetProperties()(0).Name
EDIT Оказывается, где можно использовать выражения, можно также использовать проекцию для такого рода отражения (код на языке C#).
public static class ObjectExtensions {
public static string GetVariableName<T>(this T obj) {
System.Reflection.PropertyInfo[] objGetTypeGetProperties = obj.GetType().GetProperties();
if(objGetTypeGetProperties.Length == 1)
return objGetTypeGetProperties[0].Name;
else
throw new ArgumentException("object must contain one property");
}
}
class Program {
static void Main(string[] args) {
Console.WriteLine(Console.WriteLine(new { (new MyClass()).MyItem}.GetVariableName()););
}
}
С таким решением класс может иметь любое количество свойств, можно получить любые другие их имена.
Вы всегда можете использовать статический класс, который содержит строковые
константы, вместо того, чтобы передавать в строку
буквально:
public static class ObjectForStrongTyping
{
public const string MyItem = "MyItem";
public const string MyOtherItem = "MyOtherItem";
// ...
}
Ваш код тогда станет:
SomeFunc(ObjectForStrongTyping.MyItem);
Это решение работает как на C#, так и на VB.NET, но синтаксис VB.NET для лямбда-функций не так чист, что, вероятно, сделало бы это решение менее привлекательным в VB. Мои примеры будут на C#.
Вы можете достичь желаемого эффекта, используя особенности лямбда-функции и дерева выражений на C# 3. В принципе, вы бы написали функцию-обертку под названием SomeFuncHelper и вызвали ее так:
MyClass objForStrongTyping = new MyClass();
SomeFuncHelper(() => objForStrongTyping.MyItem);
SomeFuncHelper реализуется следующим образом:
void SomeFuncHelper(Expression<Func<object>> expression)
{
string propertyName = /* get name by examining expression */;
SomeFunc(propertyName);
}
Выражение лямбда () => objForStrongTyping.MyItem
транслируется в объект Expression, который передается в SomeFuncHelper. SomeFuncHelper исследует выражение, вытаскивает имя свойства и вызывает SomeFunc. В моём беглом тесте следующий код работает для извлечения имени свойства, предполагая, что SomeFuncHelper вызывается всегда, как показано выше (т.е. () => someObject.SomeProperty
):
propertyName = ((MemberExpression) ((UnaryExpression) expression.Body).Operand).Member.Name;
Вероятно, вам захочется прочитать на деревьях выражений и поработать с кодом, чтобы сделать его более надёжным, но это общая идея.
Обновление: Это похоже на решение Джейсона, но позволяет немного упростить выражение лямбда внутри вызова вспомогательной функции (() => obj.Property
вместо (SomeType obj) => obj.Property
). Конечно, это будет проще, если у вас уже есть экземпляр этого типа.