Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
P
protobuf
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
protobuf
Commits
ef3464df
Commit
ef3464df
authored
Jul 10, 2015
by
Jon Skeet
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Oneof reflection support. (Generated code changes in next commit.)
parent
5b9288e4
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
87 additions
and
34 deletions
+87
-34
GeneratedMessageTest.cs
csharp/src/ProtocolBuffers.Test/GeneratedMessageTest.cs
+20
-0
FieldAccessorTable.cs
csharp/src/ProtocolBuffers/FieldAccess/FieldAccessorTable.cs
+27
-3
OneofAccessor.cs
csharp/src/ProtocolBuffers/FieldAccess/OneofAccessor.cs
+26
-31
ReflectionUtil.cs
csharp/src/ProtocolBuffers/FieldAccess/ReflectionUtil.cs
+13
-0
csharp_message.cc
src/google/protobuf/compiler/csharp/csharp_message.cc
+1
-0
No files found.
csharp/src/ProtocolBuffers.Test/GeneratedMessageTest.cs
View file @
ef3464df
...
...
@@ -734,5 +734,25 @@ namespace Google.Protobuf
var
message
=
SampleMessages
.
CreateFullTestAllTypes
();
Assert
.
Throws
<
InvalidCastException
>(()
=>
message
.
Fields
[
TestAllTypes
.
SingleBoolFieldNumber
].
GetValue
(
new
TestMap
()));
}
[
Test
]
public
void
Reflection_Oneof
()
{
var
message
=
new
TestAllTypes
();
var
fields
=
message
.
Fields
;
Assert
.
AreEqual
(
1
,
fields
.
Oneofs
.
Count
);
var
oneof
=
fields
.
Oneofs
[
0
];
Assert
.
AreEqual
(
"oneof_field"
,
oneof
.
Descriptor
.
Name
);
Assert
.
IsNull
(
oneof
.
GetCaseFieldDescriptor
(
message
));
message
.
OneofString
=
"foo"
;
Assert
.
AreSame
(
fields
[
TestAllTypes
.
OneofStringFieldNumber
].
Descriptor
,
oneof
.
GetCaseFieldDescriptor
(
message
));
message
.
OneofUint32
=
10
;
Assert
.
AreSame
(
fields
[
TestAllTypes
.
OneofUint32FieldNumber
].
Descriptor
,
oneof
.
GetCaseFieldDescriptor
(
message
));
oneof
.
Clear
(
message
);
Assert
.
AreEqual
(
TestAllTypes
.
OneofFieldOneofCase
.
None
,
message
.
OneofFieldCase
);
}
}
}
csharp/src/ProtocolBuffers/FieldAccess/FieldAccessorTable.cs
View file @
ef3464df
...
...
@@ -42,6 +42,7 @@ namespace Google.Protobuf.FieldAccess
public
sealed
class
FieldAccessorTable
{
private
readonly
ReadOnlyCollection
<
IFieldAccessor
>
accessors
;
private
readonly
ReadOnlyCollection
<
OneofAccessor
>
oneofs
;
private
readonly
MessageDescriptor
descriptor
;
/// <summary>
...
...
@@ -51,7 +52,7 @@ namespace Google.Protobuf.FieldAccess
/// <param name="type">The CLR type for the message.</param>
/// <param name="descriptor">The type's descriptor</param>
/// <param name="propertyNames">The Pascal-case names of all the field-based properties in the message.</param>
public
FieldAccessorTable
(
Type
type
,
MessageDescriptor
descriptor
,
string
[]
propertyNames
)
public
FieldAccessorTable
(
Type
type
,
MessageDescriptor
descriptor
,
string
[]
propertyNames
,
string
[]
oneofPropertyNames
)
{
this
.
descriptor
=
descriptor
;
var
accessorsArray
=
new
IFieldAccessor
[
descriptor
.
Fields
.
Count
];
...
...
@@ -65,7 +66,13 @@ namespace Google.Protobuf.FieldAccess
:
(
IFieldAccessor
)
new
SingleFieldAccessor
(
type
,
name
,
field
);
}
accessors
=
new
ReadOnlyCollection
<
IFieldAccessor
>(
accessorsArray
);
// TODO(jonskeet): Oneof support
var
oneofsArray
=
new
OneofAccessor
[
descriptor
.
Oneofs
.
Count
];
for
(
int
i
=
0
;
i
<
oneofsArray
.
Length
;
i
++)
{
var
oneof
=
descriptor
.
Oneofs
[
i
];
oneofsArray
[
i
]
=
new
OneofAccessor
(
type
,
oneofPropertyNames
[
i
],
oneof
);
}
oneofs
=
new
ReadOnlyCollection
<
OneofAccessor
>(
oneofsArray
);
}
// TODO: Validate the name here... should possibly make this type a more "general reflection access" type,
...
...
@@ -75,6 +82,10 @@ namespace Google.Protobuf.FieldAccess
/// </summary>
public
ReadOnlyCollection
<
IFieldAccessor
>
Accessors
{
get
{
return
accessors
;
}
}
public
ReadOnlyCollection
<
OneofAccessor
>
Oneofs
{
get
{
return
oneofs
;
}
}
// TODO: Review the API for the indexers. Now that we have fields and oneofs, it's not as clear...
public
IFieldAccessor
this
[
int
fieldNumber
]
{
get
...
...
@@ -84,7 +95,7 @@ namespace Google.Protobuf.FieldAccess
}
}
internal
IFieldAccessor
this
[
FieldDescriptor
field
]
public
IFieldAccessor
this
[
FieldDescriptor
field
]
{
get
{
...
...
@@ -95,5 +106,17 @@ namespace Google.Protobuf.FieldAccess
return
accessors
[
field
.
Index
];
}
}
public
OneofAccessor
this
[
OneofDescriptor
oneof
]
{
get
{
if
(
oneof
.
ContainingType
!=
descriptor
)
{
throw
new
ArgumentException
(
"OneofDescriptor does not match message type."
);
}
return
oneofs
[
oneof
.
Index
];
}
}
}
}
\ No newline at end of file
csharp/src/ProtocolBuffers/FieldAccess/OneofAccessor.cs
View file @
ef3464df
...
...
@@ -30,62 +30,57 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
using
Google.Protobuf.Descriptors
;
using
System
;
using
System.Reflection
;
namespace
Google.Protobuf.FieldAccess
{
// TODO(jonskeet): Add "new" oneof API support
/// <summary>
///
Access for an oneof
///
Reflection access for a oneof, allowing clear and "get case" actions.
/// </summary>
internal
class
OneofAccessor
<
TMessage
>
where
TMessage
:
IMessage
<
TMessage
>
public
sealed
class
OneofAccessor
{
/*
private readonly Func<TMessage, object> caseDelegate;
private readonly Func<TBuilder, IBuilder> clearDelegate;
private MessageDescriptor descriptor;
private
readonly
Func
<
object
,
int
>
caseDelegate
;
private
readonly
Action
<
object
>
clearDelegate
;
private
OneofDescriptor
descriptor
;
internal OneofAccessor(
MessageDescriptor descriptor, string name
)
internal
OneofAccessor
(
Type
type
,
string
propertyName
,
OneofDescriptor
descriptor
)
{
this.descriptor = descriptor;
MethodInfo clearMethod = typeof(TBuilder).GetMethod("Clear" + name);
PropertyInfo caseProperty = typeof(TMessage).GetProperty(name + "Case");
if (clearMethod == null || caseProperty == null)
PropertyInfo
property
=
type
.
GetProperty
(
propertyName
+
"Case"
);
if
(
property
==
null
||
!
property
.
CanRead
)
{
throw new ArgumentException("Not all required properties/methods available
for oneof
");
throw
new
ArgumentException
(
"Not all required properties/methods available"
);
}
this
.
descriptor
=
descriptor
;
caseDelegate
=
ReflectionUtil
.
CreateFuncObjectT
<
int
>(
property
.
GetGetMethod
());
clearDelegate = ReflectionUtil.CreateDelegateFunc<TBuilder, IBuilder>(clearMethod
);
c
aseDelegate = ReflectionUtil.CreateUpcastDelegate<TMessage>(caseProperty.GetGetMethod()
);
this
.
descriptor
=
descriptor
;
MethodInfo
clearMethod
=
type
.
GetMethod
(
"Clear"
+
propertyName
);
c
learDelegate
=
ReflectionUtil
.
CreateActionObject
(
clearMethod
);
}
/// <summary>
/// Indicates whether the specified message has set any field in the oneof.
/// </summary>
public bool Has(TMessage message)
{
return ((int) caseDelegate(message) != 0);
}
public
OneofDescriptor
Descriptor
{
get
{
return
descriptor
;
}
}
/// <summary>
/// Clears the oneof in the specified
builder
.
/// Clears the oneof in the specified
message
.
/// </summary>
public void Clear(
TBuilder builder
)
public
void
Clear
(
object
message
)
{
clearDelegate(
builder
);
clearDelegate
(
message
);
}
/// <summary>
/// Indicates which field in the oneof is set for specified message
/// </summary>
public
virtual FieldDescriptor GetOneofFieldDescriptor(TMessage
message)
public
FieldDescriptor
GetCaseFieldDescriptor
(
object
message
)
{
int fieldNumber =
(int)
caseDelegate(message);
int
fieldNumber
=
caseDelegate
(
message
);
if
(
fieldNumber
>
0
)
{
return descriptor.FindFieldByNumber(fieldNumber);
return
descriptor
.
ContainingType
.
FindFieldByNumber
(
fieldNumber
);
}
return
null
;
}
*/
}
}
}
csharp/src/ProtocolBuffers/FieldAccess/ReflectionUtil.cs
View file @
ef3464df
...
...
@@ -64,6 +64,19 @@ namespace Google.Protobuf.FieldAccess
return
Expression
.
Lambda
<
Func
<
object
,
object
>>(
upcast
,
parameter
).
Compile
();
}
/// <summary>
/// Creates a delegate which will cast the argument to the appropriate method target type,
/// call the method on it, then convert the result to the specified type.
/// </summary>
internal
static
Func
<
object
,
T
>
CreateFuncObjectT
<
T
>(
MethodInfo
method
)
{
ParameterExpression
parameter
=
Expression
.
Parameter
(
typeof
(
object
),
"p"
);
Expression
downcast
=
Expression
.
Convert
(
parameter
,
method
.
DeclaringType
);
Expression
call
=
Expression
.
Call
(
downcast
,
method
);
Expression
upcast
=
Expression
.
Convert
(
call
,
typeof
(
T
));
return
Expression
.
Lambda
<
Func
<
object
,
T
>>(
upcast
,
parameter
).
Compile
();
}
/// <summary>
/// Creates a delegate which will execute the given method after casting the first argument to
/// the target type of the method, and the second argument to the first parameter type of the method.
...
...
src/google/protobuf/compiler/csharp/csharp_message.cc
View file @
ef3464df
...
...
@@ -151,6 +151,7 @@ void MessageGenerator::GenerateStaticVariableInitializers(io::Printer* printer)
printer
->
Print
(
"
\"
$property_name$
\"
, "
,
"property_name"
,
GetPropertyName
(
descriptor_
->
field
(
i
)));
}
printer
->
Print
(
"}, new string[] { "
);
for
(
int
i
=
0
;
i
<
descriptor_
->
oneof_decl_count
();
i
++
)
{
printer
->
Print
(
"
\"
$oneof_name$
\"
, "
,
"oneof_name"
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment