Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I feel like I need to give a little background information on why I'm doing what I'm doing, because I want to open it to suggestions and criticism, and give hope to Blender-using XNA programmers that might read this. Considering the length of this post, please feel free to skip to the last paragraph if you don't care about the nitty-gritty details of my problem.

I'm working on an XNA Content Pipeline extension project that reads .blend files (created by Blender) and converts them to data loadable from an XNA game, to avoid having to export a new .FBX or .OBJ model from Blender every time I make any little tweak, as well as (hopefully) make some XNA-compatible support for Blender's awesome particle and physics capabilities.

Without diving too deep into Blender's inner workings, I'd like to describe my understanding of how .blend files work. Please correct me if you're more knowledgeable on the subject.

Blender saves files in "blocks" of bytes. Most of these blocks contain data representing objects and settings in the 3D scene, and the last block in the file (called the SDNA block), contains what can be thought of as very simple C-style structures, each of which has a unique identifier, as well as several fields of various types. Fields of these structures may be of simple types, such as int or float, or they may be of the types defined in the SDNA block.

For example, here's a semi-pseudo-code representation of the ID SDNA structure:

structure IDPropertyData
    void *pointer;
    ListBase group;
    int val;
    int val2;

As you can see, the fields *pointer, val, and val2 can be represented at runtime by simple values of type void* or int. The group field, however, is of type ListBase, which is defined elsewhere in the file's SDNA block.

This is where C#'s new dynamic features come to play: I've made a class (called BlenderObject) that, given an SDNA structure (it's "SDNA type"), and a chunk of bytes, behaves as an instance of that structure by storing either a simple-type value for itself, or a collection of other BlenderObject instances, each representing one of its "fields". This allows the user of my library to write code like the following:

//Get a BlendContent instance that contains the file's information.
BlendContent content = BlendContent.Read(filePath);
//Get the 0th (and only) block containing data for the scene (code "SC")
BlendFileBlock sceneBlock = content.FileBlocks["SC", 0];
//Get the BlenderObject that represents the scene
dynamic scene = sceneBlock.Object;
//Get the scene's "r" field, whose SDNA type is RenderData.
dynamic renderData = scene.r;
//Get the x and y resolution of the rendered scene
    xParts = renderData.xparts,
    yParts = renderData.yparts;

scene and renderData are both "complex" BlenderObject instances (each having a collection of fields, rather than a direct value), and xparts, and yparts are both "simple" BlenderObject instances (each having a direct, simple-type value for itself, rather than a collection of fields). Each BlenderObject behaves exactly the way you'd expect it to if its SDNA type was a concretely compiled type in the assembly, which is my goal in using dynamics to represent Blender objects.

To simplify using my library, I'm working on overloading DynamicObject's methods in a way that makes "simple" BlenderObject instances behave as their direct values. For example, let foo be a BlenderObject with a direct int-type value of, let's say, 4. I want to be able to do the following with foo:

string s = foo.ToString();

The intention of the first line is to invoke the ToString method of foo's inner value, not of foo itself, so the foo's TryInvokeMember override uses reflection to invoke Int32.ToString() on its value of 4, rather than BlenderObject.ToString() on itself. This reflective method-calling works great (and so does the same concept applied to indexers for array-type direct values), except when I try something like the following:

string s = foo.Bar();

Bar is an extension method defined in my assembly, and so reflecting foo's value of 4 obviously fails to find it, and, of course, exceptions are thrown. My question, finally, is this:

How can I find and/or cache extension methods that can be applied to an object? I know how to find extension methods with reflection, but doing this every time an extension method is called on a dynamic BlenderObject instance would be really slow. Is there a faster way to find extension methods, other than the one described in that question? If not, how should I go about interning extension methods so I only need to find them once and can quickly access them again? Sorry for the longevity, and thanks in advance for any helpful answers/comments.

share|improve this question

closed as off-topic by Josh Petrie Dec 16 '13 at 21:23

This question appears to be off-topic. The users who voted to close gave this specific reason:

  • "Programming questions that aren't specific to game development are off-topic here, but can be asked on Stack Overflow. A good rule of thumb is to ask yourself "would a professional game developer give me a better/different/more specific answer to this question than other programmers?"" – Josh Petrie
If this question can be reworded to fit the rules in the help center, please edit the question.

"Each BlenderObject behaves exactly the way you'd expect it to if its SDNA type was a concretely compiled type" - I'm a bit confused; why isn't it a concrete type? – BlueRaja - Danny Pflughoeft Jun 17 '11 at 21:59
Given they are extension methods I assume you wrote them, and since you are using reflection to find them I assume you know which one you are looking for. So, why do they need to be extension methods? can't you just make them "Helper" methods in some other static class? All that would be different is removing the "this object foo" and making it "object foo" so you can pass the instance in. – Joe Aug 26 '11 at 16:52

Browse other questions tagged or ask your own question.