Before deserialize existing .proto file i need to check whether the array property (HtmlCleanerEngineProfile[]) has already satisfied condition. If not, then i should recreate the property.
And here's the problem, after HtmlCleanerEngineProfile[] has been recreated (inside the constructor) this new property still has same value (and length) with old property.
[ProtoContract]
public class HtmlCleanerTemplate : ModelBase
{
private string _templateName;
private int _recursiveLevel = 3;
[ProtoMember(1)]
public string TemplateName
{
get => _templateName;
set => SetProperty(ref _templateName, value);
}
[ProtoMember(2), DefaultValue(3)]
public int RecursiveLevel
{
get => _recursiveLevel;
set => SetProperty(ref _recursiveLevel, value);
}
// This one..
[ProtoMember(3, OverwriteList = true)]
public HtmlCleanerEngineProfile[] EngineProfiles { get; private set; }
public HtmlCleanerTemplate()
{
var engineTypes = RetrieveEngineTypes();
if (EngineProfiles != null && EngineProfiles.Length == engineTypes.Count) return;
// 1. Clone existing to restore checked state
// 2. Recreate HtmlCleanerEngineProfile[]
var tempProfiles = EngineProfiles?.Clone() as HtmlCleanerEngineProfile[];
EngineProfiles = new HtmlCleanerEngineProfile[engineTypes.Count];
for (var i = 0; i < engineTypes.Count; i++)
{
EngineProfiles[i] = new HtmlCleanerEngineProfile
{
EngineName = engineTypes[i].Name,
EngineDescription = ReflectionUtils.GetDescription(engineTypes[i]),
};
// Restore checked state
if (tempProfiles != null && i < tempProfiles.Length)
{
// Todo: if (EngineProfiles[i].EngineName == tempEngines[i].EngineName)
EngineProfiles[i].EngineChecked = tempProfiles[i].EngineChecked;
}
}
}
private static IList<Type> RetrieveEngineTypes()
{
return ReflectionUtils
.GetTypes("ContentManager.Core.Document.Cleaner")
.Where(x => typeof(IHtmlCleanerEngine).IsAssignableFrom(x) && x.Name != typeof(IHtmlCleanerEngine).Name)
.ToList();
}
}
And the HtmlCleanerEnglineProfile
[ProtoContract]
public sealed class HtmlCleanerEngineProfile
{
internal HtmlCleanerEngineProfile() { }
[ProtoMember(1)]
public string EngineName { get; set; }
[ProtoMember(2)]
public string EngineDescription { get; set; }
[ProtoMember(3)]
public bool EngineChecked { get; set; }
}
I've trying to create a new method (same as code inside constructor) and assign [ProtoBeforeDeserialization] attribute. But still i got same result. Did I do something wrong?
Solved by adding [ProtoAfterDeserialization] attribute and [ProtoContract(SkipConstructor = true)].
[ProtoContract(SkipConstructor = true)]
public class HtmlCleanerTemplate : ModelBase
New method
[ProtoAfterDeserialization]
protected void AfterDeserialization()
{
var engineTypes = RetrieveEngineTypes();
if (EngineProfiles != null && EngineProfiles.Length == engineTypes.Count) return;
.......
}
Ctor..
public HtmlCleanerTemplate()
{
AfterDeserialization();
}
I have a function as below:
public var UpdateMapFetcher(int stationID, int typeID)
I need this function to return either string or int.
My return value is set as below
if (finaloutput == "System.String")
{
// param1[i] = Convert.ChangeType(typeID_New.ToString(), typeof(string));
returnvalue = returnvalue.ToString();
return returnvalue;
}
else if (finaloutput == "System.Int32")
{
int a=0;
a = Convert.ToInt32(returnvalue);
return a;
}
How to have either one data type as return value in dynamic environment.
My intuition tells me, that you are trying to convert string value to some type. In that case you can use:
public T UpdateMapFetcher<T>(int stationID)
{
//var someValue = "23";
return (T)Convert.ChangeType(someValue, typeof(T));
}
//then
var typed = UpdateMapFetcher<int>(6);
In case you don't know T, you can use mapping (0-int, 1-string, etc.):
public object UpdateMapFetcher(int stationID, int type)
{
var typeMap = new []{ typeof(int), typeof(string)};
//var someValue = "23";
return Convert.ChangeType(someValue, typeMap[type]);
}
//then
var untyped = UpdateMapFetcher(6, 0/*0 is int*/);
if (untyped.GetType() == typeof(int))
{ /*is int*/
}
Another solution is to use implicit conversions:
public class StringOrInt
{
private object value;
public ValueType Type { get; set; }
public static implicit operator StringOrInt(string value)
{
return new StringOrInt()
{
value = value,
Type = ValueType.String
};
}
public static implicit operator StringOrInt(int value)
{
return new StringOrInt()
{
value = value,
Type = ValueType.Int
};
}
public static implicit operator int(StringOrInt obj)
{
return (int)obj.value;
}
public static implicit operator string(StringOrInt obj)
{
return (string)obj.value;
}
}
public enum ValueType
{
String,
Int
}
And then (simplified):
public static StringOrInt UpdateMapFetcher(int stationID, int typeID)
{
if (typeID == 0)
return "Text";
return 23;
}
private static void Main(string[] args)
{
var result = UpdateMapFetcher(1, 1);
if (result.Type == ValueType.String) { }//can check before
int integer = result;//compiles, valid
string text = result;//compiles, fail at runtime, invalid cast
}
you can return an object. You'd have to subsequently check for types in your consuming method. I assume that won't be a problem in your usecase.
your method signature is therefore:
public object UpdateMapFetcher(int stationID, int typeID)
You also have the option of using the out keyword, which permits you to accept both into variables and check after the function has been called.
public void UpdateMapFetcher(int stationID, int typeID, out int intValue, out string strValue)
// or int return val and out string value
public int UpdateMapFetcher(int stationID, int typeID, out string strValue)
With the use appearing something like this:
int intVal;
string strVal;
UpdateMapFetcher(stationID, typeID, out intVal, out strVal);
if (strVal != null)
{
doSomethingWithString(strVal);
}
else
{
doSomethingWithInt(intVal);
}
Frankly, I would just return a Tuple, with string being non-null indicating string value to use, and null as indicator for int return
public Tuple<string, int> UpdateMapFetcher(int stationID, int typeID) {
if (finaloutput == "System.String")
{
// param1[i] = Convert.ChangeType(typeID_New.ToString(), typeof(string));
returnvalue = returnvalue.ToString();
return new Tuple<string, int>(returnvalue, 0);
}
else if (finaloutput == "System.Int32")
{
int a=0;
a = Convert.ToInt32(returnvalue);
return new Tuple<string, int>(null, a);
}
}
On consumer side
var rc = UpdateMapFetcher( .... );
if (rc.Item1 != null) {
// code to use string value
} else {
// code to use int value
}
I would choose to return an object of new class which might look like this:
class Result {
public string StringValue { get; }
public string Int32Value { get; }
public bool IsString { get; }
public bool IsInt32 { get; }
public Result(string value) {
StringValue = value;
IsString = true;
}
public Result(int value) {
Int32Value = value;
IsInt32 = true;
}
}
This way you can check which Type is it by using Isxxx property. You can also enhance this with validation in value geters. F. e., for string it might look like this:
public string StringValue {
get {
if (IsString)
return m_stringValue;
throw new InvalidOperationException("Value is not a string.");
}
}
You can't really do exactly that, but there are several ways to do more or less what you want. You'd probably be better off change the design a little though.
Two ideas:
Either change your code to use two different methods, and call each of them as needed instead.
..Or return an object, which you can cast however you like..
..Or, use a generic method with TypeDescriptor, like the following.
Note that we here convert the value to string first even if it was an int, since we can then use a common method ConvertFromString() to convert it to whatever type T was.
public T UpdateMapFetcher<T>(int stationID, int typeID) {
// To allow parsing to the generic type T:
var converter = System.ComponentModel.TypeDescriptor.GetConverter(typeof(T));
if(converter != null)
{
return (T)converter.ConvertFromString(returnvalue.ToString());
}
else
{
return default(T);
}
}
Usage:
var result = MyExtensions.UpdateMapFetcher<string>(1, 2);
or:
var result = MyExtensions.UpdateMapFetcher<int>(1, 2);
You can return Object and cast to type which you want.
public Object UpdateMapFetcher(int stationID, int typeID)
if (finaloutput == "System.String")
{
// param1[i] = Convert.ChangeType(typeID_New.ToString(), typeof(string));
returnvalue = returnvalue.ToString();
return returnvalue;
}
else if (finaloutput == "System.Int32")
{
int a=0;
a = Convert.ToInt32(returnvalue);
return a;
}
A type that can contain either one type or another is usually called (unsurprisingly) Either. It is a special case of a sum type, basically a discriminated union, tagged union, or disjoint union with exactly two cases (instead of an arbitrary number).
Unfortunately, there does not exist an implementation of an Either type in the standard libraries, but there are plenty of implementations to be found on Google, GitHub, and elsewhere … and porting one of the existing implementations from e.g. Haskell or Scala isn't that hard, either.
It looks a bit like this (forgive my code, I don't actually know C♯ that well):
using System;
abstract class Either<A, B>
{
public abstract bool IsLeft { get; }
public abstract bool IsRight { get; }
public abstract A Left { get; }
public abstract B Right { get; }
public abstract A LeftOrDefault { get; }
public abstract B RightOrDefault { get; }
public abstract void ForEach(Action<A> action);
public abstract void ForEach(Action<B> action);
public abstract void ForEach(Action<A> leftAction, Action<B> rightAction);
private sealed class L : Either<A, B>
{
private A Value { get; }
public override bool IsLeft => true;
public override bool IsRight => false;
public override A Left => Value;
public override B Right { get { throw new InvalidOperationException(); } }
public override A LeftOrDefault => Value;
public override B RightOrDefault => default(B);
public override void ForEach(Action<A> action) => action(Value);
public override void ForEach(Action<B> action) {}
public override void ForEach(Action<A> leftAction, Action<B> rightAction) => leftAction(Value);
internal L(A value) { Value = value; }
}
private sealed class R : Either<A, B>
{
private B Value { get; }
public override bool IsLeft => false;
public override bool IsRight => true;
public override A Left { get { throw new InvalidOperationException(); } }
public override B Right => Value;
public override A LeftOrDefault => default(A);
public override B RightOrDefault => Value;
public override void ForEach(Action<A> action) {}
public override void ForEach(Action<B> action) => action(Value);
public override void ForEach(Action<A> leftAction, Action<B> rightAction) => rightAction(Value);
internal R(B value) { Value = value; }
}
public static Either<A, B> MakeLeft(A value) => new L(value);
public static Either<A, B> MakeRight(B value) => new R(value);
}
And you'd use it like this:
static class Program
{
public static void Main()
{
var input = Console.ReadLine();
int intResult;
var result = int.TryParse(input, out intResult) ? Either<int, string>.MakeLeft(intResult) : Either<int, string>.MakeRight(input);
result.ForEach(r => Console.WriteLine("You passed me the integer one less than " + ++r), r => Console.WriteLine(r));
}
}
How to mock this class in nUnit Tests?
public class OpenDataQuery: PagedQuery, IOpenDataQuery
{
private static Dictionary<string, SortItem> m_sortModes;
protected override Dictionary<string, SortItem> SortModes
{
get
{
if (m_sortModes == null)
{
m_sortModes = new Dictionary<string, SortItem>();
AddSortMode(m_sortModes, new SortItem(ObjectExtensions.GetNameFromExpression<OpenDataCategoriesModel, string>(m => m.Name), "Наименование ↑", true) { IsDefault = true });
AddSortMode(m_sortModes, new SortItem(ObjectExtensions.GetNameFromExpression<OpenDataCategoriesModel, string>(m => m.Name), "Наименование ↓"));
}
return m_sortModes;
}
}
public IEnumerable<OpenDataCategoriesModel> OpenDataCategories { get; set; }
public string OpenDataTags { get; set; }
}
and
public abstract class PagedQuery : IPagedQuery
{
private const int DEFAULT_PAGE = 1;
private const int DEFAULT_COUNT = 5;
private int? m_page;
private int? m_count;
private int? m_total;
private string m_sort;
public int? Page
{
get
{
if (m_page == null || m_page <= 0)
{
return DEFAULT_PAGE;
}
return m_page;
}
set { m_page = value; }
}
public int? Count
{
get
{
if (m_count == null || m_count <= 0)
{
return DEFAULT_COUNT;
}
return m_count;
}
set { m_count = value; }
}
public int? Total
{
get
{
if (m_total == null || m_total <= 0)
{
return 0;
}
return m_total;
}
set { m_total = value; }
}
public string SearchQuery { get; set; }
protected virtual Dictionary<string, SortItem> SortModes
{
get { return null; }
}
public string Sort
{
get
{
var sortMode = GetSortMode(m_sort);
if (sortMode == null)
{
var defaultSort = (from i in SortModes where i.Value.IsDefault select i).FirstOrDefault();
if (!string.IsNullOrWhiteSpace(defaultSort.Key))
{
return defaultSort.Key;
}
return (from i in SortModes select i.Key).First();
}
return m_sort;
}
set
{
m_sort = value;
}
}
protected void AddSortMode(Dictionary<string, SortItem> sortModes, SortItem sortItem)
{
sortModes.Add(
String.Format(
"{0}{1}",
sortItem.FieldName.ToLower(),
sortItem.Asc ? "asc" : "desc"
),
sortItem
);
}
private SortItem GetSortMode(string sort)
{
if (SortModes == null || string.IsNullOrWhiteSpace(sort) ||
!SortModes.ContainsKey(sort.ToLower()))
{
return null;
}
return SortModes[sort.ToLower()];
}
public IOrderBy GetOrderBy()
{
var item = GetCurrentSortItem();
if (item == null)
{
return null;
}
if (item.Asc)
{
return new OrderBy(item.FieldName);
}
return new OrderByDesc(item.FieldName);
}
public SortItem GetCurrentSortItem()
{
return GetSortMode(Sort);
}
public Dictionary<string, SortItem> GetSortItems()
{
return SortModes;
}
}
and
public interface IOpenDataQuery : IPagedQuery
{
string OpenDataTags { get; set; }
}
I have some service method, that used openDataQuery class in parameters and in unit test i am trying mock this class, but this doesn't work:
public partial class OpenDataQueryRepository : Mock<OpenDataQuery>
{
public OpenDataQueryRepository(MockBehavior mockBehavior = MockBehavior.Strict)
: base(mockBehavior)
{
var opendataQuery = new Mock<IOpenDataQuery>();
var pagedQuery = opendataQuery.As<IPagedQuery>();
this.Setup(p=>p.GetOpenDataCategoriesMain(pagedQuery.Object,outttl)).Returns(OpenDataCategories);
}
}
I know that i should use Moq.Protected() for protected methods, but i don't know how use it correctly in this case. Please help me.
UPDATE:
I am testing this controller:
public class ODOpenDataController : ODBaseController
{
private readonly IOpenDataProvider m_openDataProvider;
public ODOpenDataController(IOpenDataProvider openDataProvider)
{
m_openDataProvider = openDataProvider;
}
public ActionResult Index(OpenDataQuery query)
{
int total;
query.OpenDataCategories = m_openDataProvider.GetOpenDataCategoriesMain(query, out total)
query.Total = total;
return View(query);
}
}
Test:
[Test]
public void Index_Test()
{
var opendataController = new ODOpenDataController(new OpenDataRepository().Object);
var result = opendataController.Index(new OpenDataQuery()) as ViewResult;
var model = result.Model as OpenDataQuery;
Assert.IsTrue(model.OpenDataCategories.Count() == 1);
}
[AttributeUsage(AttributeTargets.Method,AllowMultiple=true)]
public class MethodId : Attribute
{
private int mId;
public MethodId(int mId)
{
this.mId = mId;
}
public int methodId
{
get { return this.mId; }
set { this.mId = value; }
}
}
public class Methods
{
[MethodId(1)]
public void square()
{ }
[MethodId(2)]
public void Notify()
{ }
}
How to access square() in main() or in any other class with the help of MethodId?
private static MethodInfo GetMethodInfo(int id)
{
return typeof(Methods).GetMethods().
Where(x => x.GetCustomAttributes(false).OfType<MethodId>().Count() > 0)
.Where(x => x.GetCustomAttributes(false).OfType<MethodId>().First().methodId == id)
.First();
}
And usage:
var methodInfo = GetMethodInfo(1);
methodInfo.Invoke(new Methods(), null);
NOTE:
This solution is only meant to display how to do it. Not omptimised for performance. Ideally you would cache the methodInfos.
I have a class Client like that:
public class Client
{
public Person Pers { get; set; }
}
And I have 2 Person´s child class :
public class PersonType1 : Person {...}
public class PersonType2 : Person {...}
So, my Client could be PersonType1 or PersonType2...
I load 2 Client using NHibernate... And after that, I´m trying to compare than (the difference are on PersonType1 and PersonType2 attributes)...
I tried that:
public class ClientComparer : IComparer<Client>
{
public int Compare(Client __c1, Client __c2)
{
string _name1 = __c1.Person.GetType().Equals(typeof(PersonType2)) ? ((PersonType2)(__c1.Person)).Type2Att : ((PersonType1)(__c1.Person)).Type1Att ;
string _name2 = __c2.Person.GetType().Equals(typeof(PersonType2)) ? ((PersonType2)(__c2.Person)).Type2Att : ((PersonType1)(__c2.Person)).Type1Att;
if (_name1 == null)
{
if (_name2 == null)
{
return 0;
}
return -1;
}
if (_name2 == null)
{
return 1;
}
return _name1.CompareTo(_name2);
}
}
The problem is that __c1.Person.GetType() returs PersonProxy127b2a2f44f446089b336892a673643b instead of the correct type... It´s because of NHibernate...
How can I do that ? Ideas?
Thanks
Rather than having two different attributes on PersonType1 and PersonType2, define a single property in the base class Person and override it in each of the child classes. Using polymorphic behavior rather than explicit type-checking is better in any case, and essential when you're using NHibernate's proxied classes. Something like this might accomplish what you want:
public class Person
{
public string Name {get;}
}
public class PersonType2 : Person
{
private string something;
public override string Name
{
get
{
return something;
}
set
{
something = value;
}
}
}
public class PersonType2 : Person
{
private string somethingElse;
public override string Name
{
get
{
return somethingElse;
}
set
{
somethingElse = value;
}
}
}
public class Client
{
public int Compare(Client __c1, Client __c2)
{
return __c1.Pers.Name.CompareTo(__c2.Pers.Name);
}
}
Use the is operator instead of GetType():
public class ClientComparer : IComparer<Client>
{
public int Compare(Client __c1, Client __c2)
{
string _name1 = GetName(__c1.Person);
string _name2 = GetName(__c2.Person);
if (_name1 == null)
{
if (_name2 == null)
{
return 0;
}
return -1;
}
if (_name2 == null)
{
return 1;
}
return _name1.CompareTo(_name2);
}
private string GetName(Person person)
{
if (person is Person1)
{
return ((Person1)person).Type1Att;
}
else if (person is Person2)
{
return ((Person2)person).Type2Att;
}
else
{
throw new ArgumentException("Unhandled Person type.");
}
}
}