tags:

views:

117

answers:

3

I have the following LINQ that is causing my obfuscator to break.

.Where(f => f.FileName == fileName).OrderByDescending(f => f.Position).FirstOrDefault();

Is there another way I could reword this LINQ statement to test against my obfuscator?

I've reported the bug, but it could take 1-2 months to fix, so I need to try recode this LINQ in the meantime.

Update:

The exact cause in the LINQ is :

.Where(f => f.FileName == fileName)
+3  A: 

How exactly does the problem manifest? Since the C# expression compiler (used in the LINQ above) uses the memberinfo tokens directly (rather than relying on strings as reflection), I can't see that you could do any better. Likewise, assuming it is an IL obfuscator (not a source obfuscator), re-writing it as a query expression should achieve nothing, nix, zip, zero and nada. You you can try...

var first = (from f in [whatever]
             where f.FileName == fileName
             orderby f.Position descending
             select f).FirstOrDefault();

What exactly happens?


Edit based on comment: if the problem is the "capture", you could try manually building the expression with a constant (instead of a captured value) - where Foo is your type:

    var param = Expression.Parameter(typeof(Foo), "f");
    var body = Expression.Equal(Expression.PropertyOrField(param, "FileName"),
        Expression.Constant(filename));
    var predicate = Expression.Lambda<Func<Foo, bool>>(body, param);

then use:

    .Where(predicate).OrderByDescending(f => f.Position).FirstOrDefault();

The problem, of course, is convincing it that "FileName" and Foo.FileName must stay the same...


And here's a version that doesn't need the string:

    Expression<Func<Foo, string>> liftFileName = foo => foo.FileName;
    var predicate = Expression.Lambda<Func<Foo, bool>>(
        Expression.Equal(liftFileName.Body, Expression.Constant(filename)),
        liftFileName.Parameters);
Marc Gravell
When I do a release build, the post build event for the obfuscator fails with a reference to undefined class, and another error - Error occured during processing of input file '[sourceFile]' --> ilasm.exe: warning -- Nested class has non-nested visibility (0x00000001), changed to nested (0x00000002).
JL
@JL - hmmm... that sounds like the "fileName" capture - we *might* be able to fix that; two seconds...
Marc Gravell
Seems like your LINQ has the same problem as the original. Exact same error. I also decided to do a quick empty foreach loop through the collection, and that behaved and compiled.
JL
@JL - see update
Marc Gravell
@JL - and another update to remove the "FileName" string.
Marc Gravell
@Marc, Is that the exact code I need to use? Can you explain the theory please a bit more?
JL
Where clause has some invalid arguments.
JL
@JL - the C# compiler uses object capture. What I have posted *should* work, or something very much like it. I've just validated it against a test model I have locally, and it worked first time.
Marc Gravell
test C#: `var list = ctx.Table1s.Where(predicate).ToList();` - generated TSQL: `SELECT [t0].[FileName] FROM [dbo].[Table1] AS [t0] WHERE [t0].[FileName] = @p0`
Marc Gravell
@Marc, I should have stated up front that I am using Linq for objects, not SQL sorry!
JL
@JL; then just call `.Compile()` on the predicate.
Marc Gravell
A: 

In the presence of a broken tool, it is impossible to provide a guaranteed fix. You'll have to tinker with it. Try swapping Where and OrderBy.... Perhaps FirstOrDefault() is breaking, so maybe do that part by hand. In fact, even OrderBy... can probably be replace with a sort. There's a bunch of other stuff you could try.

BTW, Is this LINQ-to-SQL or LINQ-to-Objects? They behave in fundamentally different ways.

Marcelo Cantos
LINQ to Objects I think, I am traversing an collection class.
JL
A: 

The solution would be to exlcude the .FileName and .Position properties from obfuscation(renaming).

To avoid having to do this on every query, switch to an obfuscator which supports LINQ-to-* such as Crypto Obfuscator.

logicnp