// // Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // using System; using System.Linq; using System.Reflection; namespace OpenTelemetry.Instrumentation.GrpcNetClient.Implementation { internal class PropertyFetcher { private readonly string propertyName; private PropertyFetch innerFetcher; public PropertyFetcher(string propertyName) { this.propertyName = propertyName; } public object Fetch(object obj) { if (this.innerFetcher == null) { var type = obj.GetType().GetTypeInfo(); var property = type.DeclaredProperties.FirstOrDefault(p => string.Equals(p.Name, this.propertyName, StringComparison.InvariantCultureIgnoreCase)); if (property == null) { property = type.GetProperty(this.propertyName); } this.innerFetcher = PropertyFetch.FetcherForProperty(property); } return this.innerFetcher?.Fetch(obj); } // see https://github.com/dotnet/corefx/blob/master/src/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/DiagnosticSourceEventSource.cs private class PropertyFetch { /// /// Create a property fetcher from a .NET Reflection PropertyInfo class that /// represents a property of a particular type. /// public static PropertyFetch FetcherForProperty(PropertyInfo propertyInfo) { if (propertyInfo == null) { // returns null on any fetch. return new PropertyFetch(); } var typedPropertyFetcher = typeof(TypedFetchProperty<,>); var instantiatedTypedPropertyFetcher = typedPropertyFetcher.GetTypeInfo().MakeGenericType( propertyInfo.DeclaringType, propertyInfo.PropertyType); return (PropertyFetch)Activator.CreateInstance(instantiatedTypedPropertyFetcher, propertyInfo); } /// /// Given an object, fetch the property that this propertyFetch represents. /// public virtual object Fetch(object obj) { return null; } private class TypedFetchProperty : PropertyFetch { private readonly Func propertyFetch; public TypedFetchProperty(PropertyInfo property) { this.propertyFetch = (Func)property.GetMethod.CreateDelegate(typeof(Func)); } public override object Fetch(object obj) { if (obj is TObject o) { return this.propertyFetch(o); } return null; } } } } }