可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I'm reading and learning about reflection in C#. It would be fine to know how can it help me in my daily work, so I want people with more experience than me tell me samples or ideas about what kinds of things can we achieve using it, or how can we reduce de amount of code that we write.
Thanks.
回答1:
I recently used it to add custom attributes to fields in my enum:
public enum ShapeName
{
// Lines
[ShapeDescription(ShapeType.Line, "Horizontal Scroll Distance", "The horizontal distance to scroll the browser in order to center the game.")]
HorizontalScrollBar,
[ShapeDescription(ShapeType.Line, "Vertical Scroll Distance", "The vertical distance to scroll the browser in order to center the game.")]
VerticalScrollBar,
}
Using reflection to get the field:
public static ShapeDescriptionAttribute GetShapeDescription(this ShapeName shapeName)
{
Type type = shapeName.GetType();
FieldInfo fieldInfo = type.GetField(shapeName.ToString());
ShapeDescriptionAttribute[] attribs = fieldInfo.GetCustomAttributes(typeof(ShapeDescriptionAttribute), false) as ShapeDescriptionAttribute[];
return (attribs != null && attribs.Length > 0) ? attribs[0] : new ShapeDescriptionAttribute(ShapeType.NotSet, shapeName.ToString());
}
The attribute class:
[AttributeUsage(AttributeTargets.Field)]
public class ShapeDescriptionAttribute: Attribute
{
#region Constructor
public ShapeDescriptionAttribute(ShapeType shapeType, string name) : this(shapeType, name, name) { }
public ShapeDescriptionAttribute(ShapeType shapeType, string name, string description)
{
Description = description;
Name = name;
Type = shapeType;
}
#endregion
#region Public Properties
public string Description { get; protected set; }
public string Name { get; protected set; }
public ShapeType Type { get; protected set; }
#endregion
}
回答2:
Generally speaking Reflection allows you access to metadata about objects. Combining Reflection with other techniques allows you to make your program more dynamic. For instance you can load a DLL and determine if it contains an implementation of an interface. You could use this to discover dll's that support functionality at runtime. Use could use this to extend an application without a recompilation and without having to restart it.
Intellisense in Visual Studio uses reflection to give you information about the objects you are using.
Note that using Reflection comes at a cost. Reflecting an object can be slow. But if you need it Reflection is a very usefull tool.
回答3:
One use among many: you can make a plug-in architecture where you specify the name of the class-to-use in a configuration file. Using reflection you can take this string and create an instance of the object requested. If that object implements a known interface, then you can use it through ordinary (non reflection) code.
回答4:
It is invaluable for library code that doesn't have any need to know about the caller - like with generics, but richer access to the data. Examples:
- ORMs (materialization etc)
- serialization / deserialization
- object cloning / deep copy
- UI / binding code (strictly this is ComponentModel, but you can mix the two - for example, HyperDescriptor)
You should of course try to minimise the amount of reflection you do, but you can mitigate the cost by caching delegates from Delegate.CreateDelegate
/ Expression
/ DynamicMethod
回答5:
I've used reflection to allow me more flexibility meeting constantly changing requirements. That is, the customer kept changing their minds as to where to place a database table within a database. All I did was have the object self inspect its fields and call the object constructors of those fields within the object itself. Then, if one table should be found somewhere else? Click, paste, done.
This did not go out in final production, mind you, but during the iterative phase removed some of the boilerplate I would need to change.
回答6:
I used reflection to facilitate the translation of controls like labels and buttons on our forms. Using reflection I would go through all the controls on my form and write the controls name,text and title to a XML file. After the controls title and text are translated in the XML, the file is read back in setting every control's title and text found in the XML to it's translated values.
Our forms need to be translated to several different languages and using reflection helped us to save a lot of time.
回答7:
The properties window in VS is reflection based - if you make a user control you can modify any properties on it from the PropertyGrid
(its also a control you can use if you want) instantly. Of course you can add attributes to enhance how it is displayed (which are accessed via reflection).
I've also used it to implement a custom binary serialization class.
Here I have a class where I use reflection to serialize / de-serialize it - and provide attributes for additional UI information.
[TypeConverter(typeof(IndexedExpandableObjectConverter))]
[BinarySerializeable]
public sealed class Socket
{
#region Fields (7)
[SerializedPosition(0)]
Byte _mode = 1;
...
[SerializedPositionAttribute(4)]
UInt16 _localPort;
...
#region Properties (5)
[DisplayName("Listning Port")]
[Description("The port which the socket will listen for connections on")]
[DisplayIndex (0)]
public UInt16 LocalPort
{
get { return _localPort; }
set { _localPort = value; }
}
...
And serialization function - as you can see, it just takes an object and the byte order (endianness) you want. Everything else is determined by reflection. The default SerializationProvider
works using SerializedPosition
attributes on fields within the object (private or not).
public static Byte[] Serialize(Object obj, ByteOrder streamOrder)
{
var provider = GetProvider(obj);
if (provider.CanSerialize(obj.GetType()))
return provider.Serialize(obj, streamOrder);
throw new ArgumentException(obj.GetType() + " is non-serialisable by the specified provider '" + provider.GetType().FullName + "'.");
}
private static IBinarySerializatoinProvider GetProvider(Object obj)
{
var providerAttrib = Reflector.GetAttribute<BinarySerializationProviderAttribute>(obj);
if (providerAttrib != null)
return CreateProvider(providerAttrib.ProviderType);
return CreateProvider(typeof(SerializationProvider));
}
回答8:
This is way to execute methods based on a enum or a magic string...
public enum ReflectionTestMethods
{
MethodA,
MethodB,
MethodC
}
public class ReflectionTest
{
public void Execute(ReflectionTestMethods method)
{
MethodInfo methodInfo = GetType().GetMethod(method.ToString()
, BindingFlags.Instance | BindingFlags.NonPublic);
if (methodInfo == null) throw new NotImplementedException(method.ToString());
methodInfo.Invoke(this, null);
}
private void MethodA()
{
Debug.Print("MethodA");
}
private void MethodB()
{
Debug.Print("MethodB");
}
private void MethodC()
{
Debug.Print("MethodC");
}
}
But this is maybe a better solution...
public class ActionTest
{
private readonly Dictionary _actions = new Dictionary();
public ActionTest()
{
_actions.Add(ReflectionTestMethods.MethodA.ToString(), new Action(MethodA));
_actions.Add(ReflectionTestMethods.MethodB.ToString(), new Action(MethodB));
_actions.Add(ReflectionTestMethods.MethodC.ToString(), new Action(MethodC));
}
public void Execute(ReflectionTestMethods method)
{
if (!_actions.ContainsKey(method.ToString()))
throw new NotImplementedException(method.ToString());
_actions[method.ToString()]();
}
private void MethodA()
{
Debug.Print("MethodA");
}
private void MethodB()
{
Debug.Print("MethodB");
}
private void MethodC()
{
Debug.Print("MethodC");
}
}
回答9:
I've only used reflection in production code once. It was a situation where I had to make adjustments to what - up to that point in time - had been standardised usage of a particular class method in a startup routine (sorry not to be more specfic - it was a while ago and the details are hazy). The only way round the problem was to introduce a different version of the method and examine various criteria/code conditions etc. at runtime to determine which method I should be calling. It was a pretty compact piece of code that provided a succint solution to what would otherwise have been a messy problem to solve.
回答10:
Here are some things I've used Reflection for that would be extremely difficult or impossible without it:
- My C# port of the StringTemplate templating engine. Reflection is used to retrive properties of dynamic objects.
- A CLI JIT compiler written in managed code.
The Managed Extensibility Framework (a new .NET library) uses reflection to:
- Locate and compose parts, including applying Imports.
- It avoids loading assemblies for execution until their contents are required.
回答11:
I guess that a "stand alone" application, where every object you use is known at compile time, you don't use reflection much.
But when you write library or framework code that should use objects that are not known (completely - you might know about interfaces or baseclasses) at compile time, reflection could be invaluable to work with those objects.
回答12:
I use it for:
- Dependency injection
- Workarounds for Microsofts lack of motivation to add things like "covariant / contravariant generic" and "new() constraints with parameters"
- Aspect oriented programming (to some extent, mostly I use PostSharp)
回答13:
Reflections are nice for "late binding" solutions where you do not want to have a physical reference connected to your project but rather "connect" it later on. That way if the reference is not there and it is not critical, you get no unhandlish errors of missing references. You get a controlled error that you can handle.
回答14:
A classic use I have for it in using Red Gate .Net Reflector to better understand the mechanics of the .Net framework itself. Ever wondered how or why a particularly framework object works the way it does or have you ever been a bit stumped as too why somethng doesn't work in the manner you thought it would?
Sometimes the documentation can be a little shabby to say the least but by using reflection and the tool by Redgate you can sniff about in the frameworks code to better understand the how/why/what of it all.
More than a few bugs have been found in the CLRs code via "MS outsiders" using reflection.