* ObjectControllerTests.cs: test: 测试批量操作
* AVObject.cs: * AVFileExtensions.cs: * MutableObjectState.cs: * AVObjectController.cs: * ObjectSubclassInfo.cs: * ObjectSubclassingController.cs:
parent
7f29ee2cbf
commit
7980d47168
|
@ -13,11 +13,9 @@ namespace LeanCloudTests {
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public async Task Save() {
|
public async Task Save() {
|
||||||
TestContext.Out.WriteLine($"before at {Thread.CurrentThread.ManagedThreadId}");
|
|
||||||
AVObject obj = AVObject.Create("Foo");
|
AVObject obj = AVObject.Create("Foo");
|
||||||
obj["content"] = "hello, world";
|
obj["content"] = "hello, world";
|
||||||
await obj.SaveAsync();
|
await obj.SaveAsync();
|
||||||
TestContext.Out.WriteLine($"{obj.ObjectId} saved at {Thread.CurrentThread.ManagedThreadId}");
|
|
||||||
Assert.NotNull(obj.ObjectId);
|
Assert.NotNull(obj.ObjectId);
|
||||||
Assert.NotNull(obj.CreatedAt);
|
Assert.NotNull(obj.CreatedAt);
|
||||||
Assert.NotNull(obj.UpdatedAt);
|
Assert.NotNull(obj.UpdatedAt);
|
||||||
|
@ -26,6 +24,8 @@ namespace LeanCloudTests {
|
||||||
[Test]
|
[Test]
|
||||||
public async Task SaveWithOptions() {
|
public async Task SaveWithOptions() {
|
||||||
AVObject account = AVObject.CreateWithoutData("Account", "5d65fa5330863b008065e476");
|
AVObject account = AVObject.CreateWithoutData("Account", "5d65fa5330863b008065e476");
|
||||||
|
account["balance"] = 100;
|
||||||
|
await account.SaveAsync();
|
||||||
AVQuery<AVObject> query = new AVQuery<AVObject>("Account");
|
AVQuery<AVObject> query = new AVQuery<AVObject>("Account");
|
||||||
query.WhereGreaterThan("balance", 80);
|
query.WhereGreaterThan("balance", 80);
|
||||||
account["balance"] = 50;
|
account["balance"] = 50;
|
||||||
|
@ -33,6 +33,20 @@ namespace LeanCloudTests {
|
||||||
TestContext.Out.WriteLine($"balance: {account["balance"]}");
|
TestContext.Out.WriteLine($"balance: {account["balance"]}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task SaveBatch() {
|
||||||
|
List<AVObject> objList = new List<AVObject>();
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
AVObject obj = AVObject.Create("Foo");
|
||||||
|
obj["content"] = "batch object";
|
||||||
|
objList.Add(obj);
|
||||||
|
}
|
||||||
|
await objList.SaveAllAsync();
|
||||||
|
objList.ForEach(obj => {
|
||||||
|
Assert.NotNull(obj.ObjectId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public async Task Fetch() {
|
public async Task Fetch() {
|
||||||
AVObject obj = AVObject.CreateWithoutData("Todo", "5d5f6039d5de2b006cf29c8f");
|
AVObject obj = AVObject.CreateWithoutData("Todo", "5d5f6039d5de2b006cf29c8f");
|
||||||
|
@ -56,5 +70,40 @@ namespace LeanCloudTests {
|
||||||
AVObject tag = obj["tag"] as AVObject;
|
AVObject tag = obj["tag"] as AVObject;
|
||||||
TestContext.Out.WriteLine($"{tag["name"]}");
|
TestContext.Out.WriteLine($"{tag["name"]}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task FetchAll() {
|
||||||
|
List<AVObject> objList = new List<AVObject> {
|
||||||
|
AVObject.CreateWithoutData("Tag", "5d64e5ebc05a8000730340ba"),
|
||||||
|
AVObject.CreateWithoutData("Tag", "5d64e5eb12215f0073db271c"),
|
||||||
|
AVObject.CreateWithoutData("Tag", "5d64e57f43e78c0068a14315")
|
||||||
|
};
|
||||||
|
await objList.FetchAllAsync();
|
||||||
|
objList.ForEach(obj => {
|
||||||
|
Assert.NotNull(obj.ObjectId);
|
||||||
|
TestContext.Out.WriteLine($"{obj.ObjectId}, {obj["name"]}");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Delete() {
|
||||||
|
AVObject obj = AVObject.Create("Foo");
|
||||||
|
obj["content"] = "hello, world";
|
||||||
|
await obj.SaveAsync();
|
||||||
|
Assert.NotNull(obj);
|
||||||
|
await obj.DeleteAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task DeleteAll() {
|
||||||
|
List<AVObject> objList = new List<AVObject>();
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
AVObject obj = AVObject.Create("Foo");
|
||||||
|
obj["content"] = "batch object";
|
||||||
|
objList.Add(obj);
|
||||||
|
}
|
||||||
|
await objList.SaveAllAsync();
|
||||||
|
await AVObject.DeleteAllAsync(objList);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ namespace LeanCloud.Storage.Internal {
|
||||||
Path = $"classes/{Uri.EscapeDataString(state.ClassName)}/{Uri.EscapeDataString(state.ObjectId)}?{AVClient.BuildQueryString(queryString)}",
|
Path = $"classes/{Uri.EscapeDataString(state.ClassName)}/{Uri.EscapeDataString(state.ObjectId)}?{AVClient.BuildQueryString(queryString)}",
|
||||||
Method = HttpMethod.Get
|
Method = HttpMethod.Get
|
||||||
};
|
};
|
||||||
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).OnSuccess(t => {
|
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken).OnSuccess(t => {
|
||||||
return AVObjectCoder.Instance.Decode(t.Result.Item2, AVDecoder.Instance);
|
return AVObjectCoder.Instance.Decode(t.Result.Item2, AVDecoder.Instance);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ namespace LeanCloud.Storage.Internal {
|
||||||
string encode = AVClient.BuildQueryString(args);
|
string encode = AVClient.BuildQueryString(args);
|
||||||
command.Path = $"{command.Path}?{encode}";
|
command.Path = $"{command.Path}?{encode}";
|
||||||
}
|
}
|
||||||
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).OnSuccess(t => {
|
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken).OnSuccess(t => {
|
||||||
var serverState = AVObjectCoder.Instance.Decode(t.Result.Item2, AVDecoder.Instance);
|
var serverState = AVObjectCoder.Instance.Decode(t.Result.Item2, AVDecoder.Instance);
|
||||||
serverState = serverState.MutatedClone(mutableClone => {
|
serverState = serverState.MutatedClone(mutableClone => {
|
||||||
mutableClone.IsNew = t.Result.Item1 == System.Net.HttpStatusCode.Created;
|
mutableClone.IsNew = t.Result.Item1 == System.Net.HttpStatusCode.Created;
|
||||||
|
@ -82,7 +82,7 @@ namespace LeanCloud.Storage.Internal {
|
||||||
Path = $"classes/{state.ClassName}/{state.ObjectId}",
|
Path = $"classes/{state.ClassName}/{state.ObjectId}",
|
||||||
Method = HttpMethod.Delete
|
Method = HttpMethod.Delete
|
||||||
};
|
};
|
||||||
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken);
|
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IList<Task> DeleteAllAsync(IList<IObjectState> states,
|
public IList<Task> DeleteAllAsync(IList<IObjectState> states,
|
||||||
|
@ -131,8 +131,8 @@ namespace LeanCloud.Storage.Internal {
|
||||||
|
|
||||||
var encodedRequests = requests.Select(r => {
|
var encodedRequests = requests.Select(r => {
|
||||||
var results = new Dictionary<string, object> {
|
var results = new Dictionary<string, object> {
|
||||||
{ "method", r.Method },
|
{ "method", r.Method.Method },
|
||||||
{ "path", r.Path },
|
{ "path", $"/{AVClient.APIVersion}/{r.Path}" },
|
||||||
};
|
};
|
||||||
|
|
||||||
if (r.Content != null) {
|
if (r.Content != null) {
|
||||||
|
@ -147,7 +147,7 @@ namespace LeanCloud.Storage.Internal {
|
||||||
{ "requests", encodedRequests }
|
{ "requests", encodedRequests }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).ContinueWith(t => {
|
AVPlugins.Instance.CommandRunner.RunCommandAsync<IList<object>>(command, cancellationToken).ContinueWith(t => {
|
||||||
if (t.IsFaulted || t.IsCanceled) {
|
if (t.IsFaulted || t.IsCanceled) {
|
||||||
foreach (var tcs in tcss) {
|
foreach (var tcs in tcss) {
|
||||||
if (t.IsFaulted) {
|
if (t.IsFaulted) {
|
||||||
|
@ -159,7 +159,7 @@ namespace LeanCloud.Storage.Internal {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var resultsArray = Conversion.As<IList<object>>(t.Result.Item2["results"]);
|
var resultsArray = t.Result.Item2;
|
||||||
int resultLength = resultsArray.Count;
|
int resultLength = resultsArray.Count;
|
||||||
if (resultLength != batchSize) {
|
if (resultLength != batchSize) {
|
||||||
foreach (var tcs in tcss) {
|
foreach (var tcs in tcss) {
|
||||||
|
|
|
@ -2,10 +2,8 @@
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace LeanCloud.Storage.Internal
|
namespace LeanCloud.Storage.Internal {
|
||||||
{
|
public class MutableObjectState : IObjectState {
|
||||||
public class MutableObjectState : IObjectState
|
|
||||||
{
|
|
||||||
public bool IsNew { get; set; }
|
public bool IsNew { get; set; }
|
||||||
public string ClassName { get; set; }
|
public string ClassName { get; set; }
|
||||||
public string ObjectId { get; set; }
|
public string ObjectId { get; set; }
|
||||||
|
@ -14,84 +12,65 @@ namespace LeanCloud.Storage.Internal
|
||||||
|
|
||||||
// Initialize serverData to avoid further null checking.
|
// Initialize serverData to avoid further null checking.
|
||||||
private IDictionary<string, object> serverData = new Dictionary<string, object>();
|
private IDictionary<string, object> serverData = new Dictionary<string, object>();
|
||||||
public IDictionary<string, object> ServerData
|
public IDictionary<string, object> ServerData {
|
||||||
{
|
get {
|
||||||
get
|
|
||||||
{
|
|
||||||
return serverData;
|
return serverData;
|
||||||
}
|
}
|
||||||
|
|
||||||
set
|
set {
|
||||||
{
|
|
||||||
serverData = value;
|
serverData = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public object this[string key]
|
public object this[string key] {
|
||||||
{
|
get {
|
||||||
get
|
|
||||||
{
|
|
||||||
return ServerData[key];
|
return ServerData[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ContainsKey(string key)
|
public bool ContainsKey(string key) {
|
||||||
{
|
|
||||||
return ServerData.ContainsKey(key);
|
return ServerData.ContainsKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Apply(IDictionary<string, IAVFieldOperation> operationSet)
|
public void Apply(IDictionary<string, IAVFieldOperation> operationSet) {
|
||||||
{
|
|
||||||
// Apply operationSet
|
// Apply operationSet
|
||||||
foreach (var pair in operationSet)
|
foreach (var pair in operationSet) {
|
||||||
{
|
|
||||||
object oldValue;
|
object oldValue;
|
||||||
ServerData.TryGetValue(pair.Key, out oldValue);
|
ServerData.TryGetValue(pair.Key, out oldValue);
|
||||||
var newValue = pair.Value.Apply(oldValue, pair.Key);
|
var newValue = pair.Value.Apply(oldValue, pair.Key);
|
||||||
if (newValue != AVDeleteOperation.DeleteToken)
|
if (newValue != AVDeleteOperation.DeleteToken) {
|
||||||
{
|
|
||||||
ServerData[pair.Key] = newValue;
|
ServerData[pair.Key] = newValue;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
ServerData.Remove(pair.Key);
|
ServerData.Remove(pair.Key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Apply(IObjectState other)
|
public void Apply(IObjectState other) {
|
||||||
{
|
|
||||||
IsNew = other.IsNew;
|
IsNew = other.IsNew;
|
||||||
if (other.ObjectId != null)
|
if (other.ObjectId != null) {
|
||||||
{
|
|
||||||
ObjectId = other.ObjectId;
|
ObjectId = other.ObjectId;
|
||||||
}
|
}
|
||||||
if (other.UpdatedAt != null)
|
if (other.UpdatedAt != null) {
|
||||||
{
|
|
||||||
UpdatedAt = other.UpdatedAt;
|
UpdatedAt = other.UpdatedAt;
|
||||||
}
|
}
|
||||||
if (other.CreatedAt != null)
|
if (other.CreatedAt != null) {
|
||||||
{
|
|
||||||
CreatedAt = other.CreatedAt;
|
CreatedAt = other.CreatedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var pair in other)
|
foreach (var pair in other) {
|
||||||
{
|
|
||||||
ServerData[pair.Key] = pair.Value;
|
ServerData[pair.Key] = pair.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IObjectState MutatedClone(Action<MutableObjectState> func)
|
public IObjectState MutatedClone(Action<MutableObjectState> func) {
|
||||||
{
|
|
||||||
var clone = MutableClone();
|
var clone = MutableClone();
|
||||||
func(clone);
|
func(clone);
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual MutableObjectState MutableClone()
|
protected virtual MutableObjectState MutableClone() {
|
||||||
{
|
return new MutableObjectState {
|
||||||
return new MutableObjectState
|
|
||||||
{
|
|
||||||
IsNew = IsNew,
|
IsNew = IsNew,
|
||||||
ClassName = ClassName,
|
ClassName = ClassName,
|
||||||
ObjectId = ObjectId,
|
ObjectId = ObjectId,
|
||||||
|
@ -101,13 +80,11 @@ namespace LeanCloud.Storage.Internal
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerator<KeyValuePair<string, object>> IEnumerable<KeyValuePair<string, object>>.GetEnumerator()
|
IEnumerator<KeyValuePair<string, object>> IEnumerable<KeyValuePair<string, object>>.GetEnumerator() {
|
||||||
{
|
|
||||||
return ServerData.GetEnumerator();
|
return ServerData.GetEnumerator();
|
||||||
}
|
}
|
||||||
|
|
||||||
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
|
||||||
{
|
|
||||||
return ((IEnumerable<KeyValuePair<string, object>>)this).GetEnumerator();
|
return ((IEnumerable<KeyValuePair<string, object>>)this).GetEnumerator();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,11 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using LeanCloud.Storage.Internal;
|
|
||||||
|
|
||||||
namespace LeanCloud.Storage.Internal
|
namespace LeanCloud.Storage.Internal {
|
||||||
{
|
internal class ObjectSubclassInfo {
|
||||||
internal class ObjectSubclassInfo
|
public ObjectSubclassInfo(Type type, ConstructorInfo constructor) {
|
||||||
{
|
|
||||||
public ObjectSubclassInfo(Type type, ConstructorInfo constructor)
|
|
||||||
{
|
|
||||||
TypeInfo = type.GetTypeInfo();
|
TypeInfo = type.GetTypeInfo();
|
||||||
ClassName = GetClassName(TypeInfo);
|
ClassName = GetClassName(TypeInfo);
|
||||||
Constructor = constructor;
|
Constructor = constructor;
|
||||||
|
@ -28,15 +21,13 @@ namespace LeanCloud.Storage.Internal
|
||||||
public IDictionary<string, string> PropertyMappings { get; private set; }
|
public IDictionary<string, string> PropertyMappings { get; private set; }
|
||||||
private ConstructorInfo Constructor { get; set; }
|
private ConstructorInfo Constructor { get; set; }
|
||||||
|
|
||||||
public AVObject Instantiate()
|
public AVObject Instantiate() {
|
||||||
{
|
|
||||||
return (AVObject)Constructor.Invoke(null);
|
return (AVObject)Constructor.Invoke(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string GetClassName(TypeInfo type)
|
internal static string GetClassName(TypeInfo type) {
|
||||||
{
|
|
||||||
var attribute = type.GetCustomAttribute<AVClassNameAttribute>();
|
var attribute = type.GetCustomAttribute<AVClassNameAttribute>();
|
||||||
return attribute != null ? attribute.ClassName : null;
|
return attribute?.ClassName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace LeanCloud.Storage.Internal {
|
||||||
|
|
||||||
private readonly ReaderWriterLockSlim mutex;
|
private readonly ReaderWriterLockSlim mutex;
|
||||||
private readonly IDictionary<string, ObjectSubclassInfo> registeredSubclasses;
|
private readonly IDictionary<string, ObjectSubclassInfo> registeredSubclasses;
|
||||||
private Dictionary<string, Action> registerActions;
|
private readonly Dictionary<string, Action> registerActions;
|
||||||
|
|
||||||
public ObjectSubclassingController() {
|
public ObjectSubclassingController() {
|
||||||
mutex = new ReaderWriterLockSlim();
|
mutex = new ReaderWriterLockSlim();
|
||||||
|
@ -38,10 +38,8 @@ namespace LeanCloud.Storage.Internal {
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsTypeValid(string className, Type type) {
|
public bool IsTypeValid(string className, Type type) {
|
||||||
ObjectSubclassInfo subclassInfo = null;
|
|
||||||
|
|
||||||
mutex.EnterReadLock();
|
mutex.EnterReadLock();
|
||||||
registeredSubclasses.TryGetValue(className, out subclassInfo);
|
registeredSubclasses.TryGetValue(className, out ObjectSubclassInfo subclassInfo);
|
||||||
mutex.ExitReadLock();
|
mutex.ExitReadLock();
|
||||||
|
|
||||||
return subclassInfo == null
|
return subclassInfo == null
|
||||||
|
@ -63,12 +61,12 @@ namespace LeanCloud.Storage.Internal {
|
||||||
// TOCTTOU bug.
|
// TOCTTOU bug.
|
||||||
mutex.EnterWriteLock();
|
mutex.EnterWriteLock();
|
||||||
|
|
||||||
ObjectSubclassInfo previousInfo = null;
|
if (registeredSubclasses.TryGetValue(className, out ObjectSubclassInfo previousInfo)) {
|
||||||
if (registeredSubclasses.TryGetValue(className, out previousInfo)) {
|
|
||||||
if (typeInfo.IsAssignableFrom(previousInfo.TypeInfo)) {
|
if (typeInfo.IsAssignableFrom(previousInfo.TypeInfo)) {
|
||||||
// Previous subclass is more specific or equal to the current type, do nothing.
|
// Previous subclass is more specific or equal to the current type, do nothing.
|
||||||
return;
|
return;
|
||||||
} else if (previousInfo.TypeInfo.IsAssignableFrom(typeInfo)) {
|
}
|
||||||
|
if (previousInfo.TypeInfo.IsAssignableFrom(typeInfo)) {
|
||||||
// Previous subclass is parent of new child, fallthrough and actually register
|
// Previous subclass is parent of new child, fallthrough and actually register
|
||||||
// this class.
|
// this class.
|
||||||
/* Do nothing */
|
/* Do nothing */
|
||||||
|
@ -91,10 +89,9 @@ namespace LeanCloud.Storage.Internal {
|
||||||
mutex.ExitWriteLock();
|
mutex.ExitWriteLock();
|
||||||
}
|
}
|
||||||
|
|
||||||
Action toPerform;
|
|
||||||
|
|
||||||
mutex.EnterReadLock();
|
mutex.EnterReadLock();
|
||||||
registerActions.TryGetValue(className, out toPerform);
|
registerActions.TryGetValue(className, out Action toPerform);
|
||||||
mutex.ExitReadLock();
|
mutex.ExitReadLock();
|
||||||
|
|
||||||
toPerform?.Invoke();
|
toPerform?.Invoke();
|
||||||
|
@ -113,10 +110,9 @@ namespace LeanCloud.Storage.Internal {
|
||||||
}
|
}
|
||||||
|
|
||||||
public AVObject Instantiate(string className) {
|
public AVObject Instantiate(string className) {
|
||||||
ObjectSubclassInfo info = null;
|
|
||||||
|
|
||||||
mutex.EnterReadLock();
|
mutex.EnterReadLock();
|
||||||
registeredSubclasses.TryGetValue(className, out info);
|
registeredSubclasses.TryGetValue(className, out ObjectSubclassInfo info);
|
||||||
mutex.ExitReadLock();
|
mutex.ExitReadLock();
|
||||||
|
|
||||||
return info != null
|
return info != null
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace LeanCloud.Storage.Internal {
|
|
||||||
/// <summary>
|
|
||||||
/// So here's the deal. We have a lot of internal APIs for AVObject, AVUser, etc.
|
|
||||||
///
|
|
||||||
/// These cannot be 'internal' anymore if we are fully modularizing things out, because
|
|
||||||
/// they are no longer a part of the same library, especially as we create things like
|
|
||||||
/// Installation inside push library.
|
|
||||||
///
|
|
||||||
/// So this class contains a bunch of extension methods that can live inside another
|
|
||||||
/// namespace, which 'wrap' the intenral APIs that already exist.
|
|
||||||
/// </summary>
|
|
||||||
public static class AVFileExtensions {
|
|
||||||
public static AVFile Create(string name, Uri uri, string mimeType = null) {
|
|
||||||
return new AVFile(name, uri, mimeType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -192,7 +192,7 @@ namespace LeanCloud {
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
public static IDictionary<String, String> GetPropertyMappings(string className) {
|
public static IDictionary<string, string> GetPropertyMappings(string className) {
|
||||||
return SubclassingController.GetPropertyMappings(className);
|
return SubclassingController.GetPropertyMappings(className);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,7 +246,7 @@ string propertyName
|
||||||
string propertyName
|
string propertyName
|
||||||
#endif
|
#endif
|
||||||
) {
|
) {
|
||||||
return GetProperty<T>(default(T), propertyName);
|
return GetProperty<T>(default, propertyName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -262,9 +262,8 @@ string propertyName
|
||||||
#else
|
#else
|
||||||
string propertyName
|
string propertyName
|
||||||
#endif
|
#endif
|
||||||
) {
|
) {
|
||||||
T result;
|
if (TryGetValue(GetFieldForPropertyName(ClassName, propertyName), out T result)) {
|
||||||
if (TryGetValue<T>(GetFieldForPropertyName(ClassName, propertyName), out result)) {
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
|
|
Loading…
Reference in New Issue