I have a problem with the protobuf-net and Android app built with IL2CPP.
Everything worked fine when I used MONO instead of IL2CPP for development. Now I need to use IL2CPP for x64 support. I didn't know System.Reflection.Emit is not supported with IL2CPP and protobuf-net is using it.
Is there a way to make the protobuf-net work with IL2CPP?
I got same problem on iOS. You have to compile ProtoModel before.
using Assembly = UnityEditor.Compilation.Assembly;
private static void BuildMyProtoModel()
{
RuntimeTypeModel typeModel = TypeModel.Create();
foreach (var t in GetTypes(CompilationPipeline.GetAssemblies(AssembliesType.Player)))
{
var contract = t.GetCustomAttributes(typeof(ProtoContractAttribute), false);
if (contract.Length > 0)
{
MetaType metaType = typeModel.Add(t, true);
// support ISerializationCallbackReceiver
if (typeof(ISerializationCallbackReceiver).IsAssignableFrom(t))
{
MethodInfo beforeSerializeMethod = t.GetMethod("OnBeforeSerialize");
MethodInfo afterDeserializeMethod = t.GetMethod("OnAfterDeserialize");
metaType.SetCallbacks(beforeSerializeMethod, null, null, afterDeserializeMethod);
}
//add unity types
typeModel.Add(typeof(Vector2), false).Add("x", "y");
typeModel.Add(typeof(Vector3), false).Add("x", "y", "z");
}
}
typeModel.Compile("MyProtoModel", "MyProtoModel.dll"); //build model
string protoSchema = typeModel.GetSchema(null);//content for .proto file, you can generate a proto file for a specific type by passing it instead of null
}
private static IEnumerable<Type> GetTypes(IEnumerable<Assembly> assemblies)
{
foreach (Assembly assembly in assemblies)
{
foreach (Type type in AppDomain.CurrentDomain.Load(assembly.name).GetTypes())
{
yield return type;
}
}
}
Copy MyProtoModel.dll from root to Plugin folder.
And use like this:
TypeModel typeModel = new MyProtoModel();
I create small project Protobuf-net & Unity:
https://github.com/koshelevpavel/UniBufExample
https://github.com/koshelevpavel/UniBuf
But it just experimental and it don't have any documents.
Small example MonoBehaviour:
https://gist.github.com/koshelevpavel/8e2d62053fc79b2bf9e2105d18b056bc
Related
I'm in a C# shared project trying to find the PCL (Profile 259) equivalent for FSharpValue.GetUnionFields.
In object browser via the C# project, I see
namespace Microsoft.FSharp.Reflection
{
[AutoOpen]
[CompilationMapping(SourceConstructFlags.Module)]
public static class FSharpReflectionExtensions
{
public static Tuple<UnionCaseInfo, object[]> FSharpValue.GetUnionFields.Static(object value, Type unionType, [OptionalArgument] FSharpOption<bool> allowAccessToPrivateRepresentation);
}
}
This appears to be what I'm looking for, but I'm unable (or don't know how) to call it from C#. Via F#, if I open the namespace, I can call the extension FSharpValue.GetUnionFields. FSharpValue.GetUnionFields does not compile from a c# PCL. I'm not experienced with F# so it could be I'm just lacking some important piece of knowledge related to F# - C# interop?
For reference, this is what I see from a F# pcl.
[<AutoOpen>]
module Microsoft.FSharp.Reflection.FSharpReflectionExtensions
open Microsoft.FSharp.Reflection
val GetUnionFields : value:obj * unionType:System.Type * ?allowAccessToPrivateRepresentation:bool -> UnionCaseInfo * obj []
Repro project here:
https://github.com/kennethito/StackOverflowReferences/tree/master/FSharpValue-GetUnionFields
Again, this requires using reflection. Since it's a PCL, it's particularly nasty, as the actual version of FSharp.Core loaded at runtime is the one that will matter.
The following should work:
public static Tuple<UnionCaseInfo, object[]> TestIt()
{
var option = new FSharpOption<int>(123);
MethodInfo method;
try
{
// If "4.4.0.0" is loaded at runtime, get directly
var t = typeof(FSharpValue);
method = t.GetRuntimeMethods().First(mi => mi.Name == "GetUnionFields");
}
catch
{
var t = typeof(FSharpReflectionExtensions);
method = t.GetRuntimeMethods().First(mi => mi.Name == "FSharp.Value.GetUnionFields.Static");
}
return (Tuple<UnionCaseInfo, object[]>)method.Invoke(null, new object[] { option, option.GetType(), null });
}
This tries to find the method directly on the type (how it's specified in FSharp.Core 4.4), and falls back to the PCL structure (as an extension method).
The following C# console application shows it working:
static void Main(string[] args)
{
Tuple<UnionCaseInfo, object[]> results = CsharpPortable.Test.TestIt();
var uci = results.Item1;
Console.WriteLine("{0}:", uci.Name);
foreach (var pi in uci.GetFields())
{
Console.WriteLine("Property: {0}", pi.Name);
}
Console.ReadKey();
}
Given an INamedTypeSymbol (that comes from an referenced assembly, not source) how can I find all types (in both source and referenced assemblies) that inherit from this type?
In my particular case, I'm looking for all types that inherit from NUnit.Framework.TestAttribute. I can get access to the named type symbol as follows:
var ws = MSBuildWorkspace.Create();
var soln = ws.OpenSolutionAsync(#"C:\Users\...\SampleInheritanceStuff.sln").Result;
var proj = soln.Projects.Single();
var compilation = proj.GetCompilationAsync().Result;
string TEST_ATTRIBUTE_METADATA_NAME = "NUnit.Framework.TestAttribute";
var testAttributeType = compilation.GetTypeByMetadataName(TEST_ATTRIBUTE_METADATA_NAME);
//Now how do I find types that inherit from this type?
I've taken a look at SymbolFinder, Compilation and INamedTypeSymbol but I haven't had any luck.
Edit: The FindDerivedClassesAsync method looks close to what I need. (I'm not 100% sure that it finds derived classes in referenced assemblies). However it's internal, so I've opened an issue.
The FindDerivedClassesAsync is indeed what you are looking for.
It finds derived classes in referenced assemblies, as you can see in the source code for DependentTypeFinder (notice the locationsInMetadata variable).
As for using it, you can always do it with reflection in the meantime:
private static readonly Lazy<Func<INamedTypeSymbol, Solution, IImmutableSet<Project>, CancellationToken, Task<IEnumerable<INamedTypeSymbol>>>> FindDerivedClassesAsync
= new Lazy<Func<INamedTypeSymbol, Solution, IImmutableSet<Project>, CancellationToken, Task<IEnumerable<INamedTypeSymbol>>>>(() => (Func<INamedTypeSymbol, Solution, IImmutableSet<Project>, CancellationToken, Task<IEnumerable<INamedTypeSymbol>>>)Delegate.CreateDelegate(typeof(Func<INamedTypeSymbol, Solution, IImmutableSet<Project>, CancellationToken, Task<IEnumerable<INamedTypeSymbol>>>), DependentTypeFinder.Value.GetMethod("FindDerivedClassesAsync", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)));
(code borrowed from Tunnel Vision Laboratories Github)
Good luck!
UPDATE:
This method has been made public by now. (source)
You can get this information using the SemanticModel exposed from the Compilation
public static IEnumerable<INamedTypeSymbol> GetBaseClasses(SemanticModel model, BaseTypeDeclarationSyntax type)
{
var classSymbol = model.GetDeclaredSymbol(type);
var returnValue = new List<INamedTypeSymbol>();
while (classSymbol.BaseType != null)
{
returnValue.Add(classSymbol.BaseType);
if (classSymbol.Interfaces != null)
returnValue.AddRange(classSymbol.Interfaces);
classSymbol = classSymbol.BaseType;
}
return returnValue;
}
This will give you a list of all the base classes as well as every interface that each base class implements. You can then filter to the INamedTypeSymbol that you are interested in:
public static IEnumerable<BaseTypeDeclarationSyntax>
FindClassesDerivedOrImplementedByType(Compilation compilation
, INamedTypeSymbol target)
{
foreach (var tree in compilation.SyntaxTrees)
{
var semanticModel = compilation.GetSemanticModel(tree);
foreach (var type in tree.GetRoot().DescendantNodes()
.OfType<TypeDeclarationSyntax>())
{
var baseClasses = GetBaseClasses(semanticModel, type);
if (baseClasses != null)
if (baseClasses.Contains(target))
yield return type;
}
}
}
I want to maintain savefile compatibility between multiple versions of my program, but this causes problems with serialization, as the assembly qualified type name changes when I increment the version number, so Type.GetType() can't find it. Is there any way to search for a type disregarding the assembly version?
Whenever a type is not found the AssembyResolvedEvent is fired.
This event can be used to check your types loaded and return that type which has the same name but ignore the version number.
http://msdn.microsoft.com/en-us/library/system.appdomain.assemblyresolve%28v=vs.110%29.aspx
EDIT:
As this was some time ago it seems that I could not recall it all correctly.
Adriano was was correct. The AssemlyResolve ist just asking for the assembly.
So additionally a SerializationBinder is needed. This sounds like work, but is quite simple! I'll try to summarize:
private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
if (args == null || string.IsNullOrEmpty(args.Name))
return null;
//if object was serialized with previous version .dll, deserialze with current version .dll (only relevant with strong names)
foreach (Assembly ass in AppDomain.CurrentDomain.GetAssemblies())
{
if ((args.Name.StartsWith("XYZ.")) // XYZ marks my namespace
&& args.Name.Contains("Culture=neutral") && args.Name.StartsWith(ass.FullName.Split(',')[0]))
return ass;
}
return null;
}
Remark: this checks only for assemblies which are already loaded!
Your SerializationBinder:
public class XYZSerializationBinder : SerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
Type curType = null;
//if object was serialized with previous version .dll, deserialze with current version .dll (only relevant with strong names)
if (!string.IsNullOrEmpty(assemblyName) && assemblyName.Contains("Culture=neutral")
&& (assemblyName.StartsWith("XYZ.")))
{
string plainAssemblyName = assemblyName.Split(',')[0];
Assembly ass = Assembly.Load(plainAssemblyName);
curType = ass.GetType(typeName);
}
else
{
curType = Type.GetType(string.Format("{0}, {1}", typeName, assemblyName));
}
if (curType == null)
{
return typeof(InvalidType);
}
return curType;
}
}
Now just use the binder!
IFormatter formatter = new BinaryFormatter();
formatter.Binder = serializationBinder;
using (FileStream fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
{
storage = formatter.Deserialize(fileStream);
}
I hope this is what you want / need!
I just figured it out!
I had to use this overload of Type.GetType() to customize the resolution:
http://msdn.microsoft.com/en-us/library/ee332932(v=vs.100).aspx
I did it like so:
type = Type.GetType(typename,
assemblyName =>
{
return AppDomain.CurrentDomain.GetAssemblies().SingleOrDefault(a => a.GetName().Name == assemblyName.Name);
},
(assembly, typeName, caseInsensitive) =>
{
if (caseInsensitive)
return assembly.GetTypes().SingleOrDefault(t => t.FullName.Equals(typeName, StringComparison.InvariantCultureIgnoreCase));
else
return assembly.GetTypes().SingleOrDefault(t => t.FullName == typeName);
});
Note the comparison of GetName().Name, as opposed to FullName, for the assemblies. This is what enables comparison of only the actual names of the assemblies, and not their versions.
I guess that you can use assembly redirection therefore:
http://msdn.microsoft.com/en-us/library/7wd6ex19(v=vs.110).aspx
You should use a SerializationBinder to resolve types.
See: http://msdn.microsoft.com/en-us/library/system.runtime.serialization.serializationbinder%28v=vs.110%29.aspx
Please note that you probably will be better off using XML or DataContract serialization that do not save type information and are also much faster.
Using the C# code provider and the ICodeCompiler.CompileAssemblyFromSource method, I am attempting to compile a code file in order to produce an executable assembly.
The code that I would like to compile makes use of features such as optional parameters and extension methods that are only available when using the language C# 4.
Having said that, the code that I would like to compile only requires (and needs) to target version 2.0 of the .NET Framework.
Using the proceeding code it is possible to avoid any compile-time errors pertaining to syntax however, the resulting assembly will target version 4.0 of the framework which is undesirable.
var compiler = new CSharpCodeProvider(
new Dictionary<string, string> { { "CompilerVersion", "v4.0" } } );
How can I make is so that the code provider targets language version 4.0 but produces an assembly that only requires version 2.0 of the framework?
You need to instruct the C# compiler (that CSharpCodeProvider uses indirectly) that you want to link to another mscorlib.dll, using the /nostdlib option. Here is a sample that should do it:
static void Main(string[] args)
{
// defines references
List<string> references = new List<string>();
// get a reference to the mscorlib you want
var mscorlib_2_x86 = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.Windows),
#"Microsoft.NET\Framework\v2.0.50727\mscorlib.dll");
references.Add(mscorlib_2_x86);
// ... add other references (System.dll, etc.)
var provider = new CSharpCodeProvider(
new Dictionary<string, string> { { "CompilerVersion", "v4.0" } });
var parameters = new CompilerParameters(references.ToArray(), "program.exe");
parameters.GenerateExecutable = true;
// instruct the compiler not to use the default mscorlib
parameters.CompilerOptions = "/nostdlib";
var results = provider.CompileAssemblyFromSource(parameters,
#"using System;
class Program
{
static void Main(string[] args)
{
Console.WriteLine(""Hello world from CLR version: "" + Environment.Version);
}
}");
}
If you run this, it should compile a program.exe file. If you run that file, it should display something like this:
Hello world from CLR version: 2.0.50727.7905
I have a flags enumeration in a .NET assembly that is getting called from an ASP.NET page. I want to have a Visual Studio build step generate a .js file that has the JavaScript equivalent in it. Are there any tools for doing this?
edit: This seems to work.
public class JavaScriptReflection
{
public static string Go(Type type)
{
if (!type.IsEnum) return;
StringBuilder sb = new StringBuilder();
sb.AppendFormat("var {0} = {{ ", type.Name);
foreach (FieldInfo fInfo in
type.GetFields(BindingFlags.Public | BindingFlags.Static))
sb.AppendFormat("{0}:{1},\r\n",
fInfo.Name,
fInfo.GetRawConstantValue().ToString());
sb.Append("};");
return sb.toString();
}
}
Script# is one thing to investigate.
I've had sucess recently using reflection on output assembly files to generate code.
Try using something like this in a console app you can call from your post-build process:
Assembly assembly = Assembly.LoadFile("FileName");
Type myEnumType = assembly.GetType("EnumName");
foreach(MemberInfo mi in myEnumType.GetMembers().Where(m => m.MemberType == MemberTypes.Field))
Console.WriteLine(mi.Name);