How do I find and replace a property using Linq in this specific scenario below:
public interface IPropertyBag { }
public class PropertyBag : IPropertyBag
{
public Property[] Properties { get; set; }
public Property this[string name]
{
get { return Properties.Where((e) => e.Name == name).Single(); }
//TODO: Just copying values... Find out how to find the index and replace the value
set { Properties.Where((e) => e.Name == name).Single().Value = value.Value; }
}
}
Thanks for helping out in advance.
Do not use LINQ because it will not improve the code because LINQ is designed to query collection and not to modify them. I suggest the following.
// Just realized that Array.IndexOf() is a static method unlike
// List.IndexOf() that is an instance method.
Int32 index = Array.IndexOf(this.Properties, name);
if (index != -1)
{
this.Properties[index] = value;
}
else
{
throw new ArgumentOutOfRangeException();
}
Why are Array.Sort() and Array.IndexOf() methods static?
Further I suggest not to use an array. Consider using IDictionary<String, Property>. This simplifies the code to the following.
this.Properties[name] = value;
Note that neither solution is thread safe.
An ad hoc LINQ solution - you see, you should not use it because the whole array will be replaced with a new one.
this.Properties = Enumerable.Union(
this.Properties.Where(p => p.Name != name),
Enumerable.Repeat(value, 1)).
ToArray();
[note: this answer was due to a misunderstanding of the question - see the comments on this answer. Apparently, I'm a little dense :(]
Is your 'Property' a class or a struct?
This test passes for me:
public class Property
{
public string Name { get; set; }
public string Value { get; set; }
}
public interface IPropertyBag { }
public class PropertyBag : IPropertyBag
{
public Property[] Properties { get; set; }
public Property this[string name]
{
get { return Properties.Where((e) => e.Name == name).Single(); }
set { Properties.Where((e) => e.Name == name).Single().Value = value.Value; }
}
}
[TestMethod]
public void TestMethod1()
{
var pb = new PropertyBag() { Properties = new Property[] { new Property { Name = "X", Value = "Y" } } };
Assert.AreEqual("Y", pb["X"].Value);
pb["X"] = new Property { Name = "X", Value = "Z" };
Assert.AreEqual("Z", pb["X"].Value);
}
I have to wonder why the getter returns a 'Property' instead of whatever datatype .Value, but I'm still curious why you're seeing a different result than what I am.
Related
I use FastMember to get values out of objects and nested objects. If a property is a string or int everything works fine. But now I want to get the values also for collections. Here is my code so far:
// Set accessor
var sourceAccessor = ObjectAccessor.Create(source);
if (sourceAccessor.Target.GetType().GetInterface(nameof(ICollection)) != null || sourceAccessor.Target.GetType().GetInterface(nameof(IEnumerable)) != null)
{
foreach (/* idk */)
{
// READ & RETURN VALUES HERE
}
}
An object could look like this:
{
Id: 1,
Surname: Doe,
Prename: John,
Professions: [
{ Name: ab },
{ Name: xy }
]
}
Which means professions would result in a problem.
Any advise how I can solve this problem? Thanks!
It's not obvious from the question what the data type of the source variable is, but you should just be able to check if the value returned by the accessor implements IEnumerable or not and act accordingly.
Here's a quick worked example that iterates over the Professions property of a 'Person' object and just dumps the ToString() representation to the console - if you wanted to dive into each Profession object using FastMember you could construct another ObjectAccessor to do it, I guess - it's not clear what your goal is once you're iterating.
The same tactic will work if you're building the ObjectAccessor directly from an array - you just check if the accessor.Target is IEnumerable and cast-and-iterate in a similar fashion.
class Program
{
static void Main(string[] args)
{
var p = new Person
{
Professions = new List<Profession>
{
new Profession("Joker"),
new Profession("Smoker"),
new Profession("Midnight toker")
}
};
var accessor = ObjectAccessor.Create(p);
var professions = accessor[nameof(Person.Professions)];
if (professions is IEnumerable)
{
foreach (var profession in (IEnumerable)professions)
{
Console.WriteLine(profession);
}
}
}
}
class Person
{
public List<Profession> Professions { get; set; }
}
class Profession
{
public string Name { get; set; }
public Profession( string name)
{
Name = name;
}
public override string ToString()
{
return Name;
}
}
I have a class that contains a list of another class which has a property that I want to check if it has more than one distinct value.
e.g
public class BasketModel
{
public BasketModel()
{
BasketOrderLines = new List<BasketOrderLine>();
}
.
.
.
public class BasketOrderLine
{
public int OrderLineId { get; set; }
public string ImageUrl { get; set; }
public string ProductType { get; set; }
.
.
Given a basket model object I want to find out if there are more than one distinct value in the ProductType.
e.g If all Product Types are "A" then that would be false, if 3 products are of type "A" and one is of type "B" then this would be true.
Cheers
Macca
Your title: "more than two distinct", your question body: "more than one distinct"
If the title is a typo:
bool notDistinctTypes = theBasket.BasketOrderLine
.Select(o => o.ProductType)
.Distinct()
.Skip(1)
.Any();
This doesn't need to enumerate all items to find out if there is more than one ProductType.
// Does this basket contains three or more types
public bool HasSeveralTypes(BasketModel basket)
{
if (basket == null)
return false;
int differentTypes = basket.BasketOrderLines
.Select(l => l.ProductType)
.Distinct()
.Count();
return (differentTypes > 2);
}
Something like this :
Public bool CheckDistinct (){
var res = basketOrderLines.Select(o => o.ProductType).Distinct ().Count ();
return res > 1;
}
There are a few ways to do this, here's one:
public class BasketModel
{
public BasketModel()
{
BasketOrderLines = new List<BasketOrderLine>();
}
public bool HasMulitpleDistinctProducts
{
get
{
if (!BasketOrderLines.Any())
{
return true; // or false?
}
return BasketOrderLines.Select(b => b.ProductType).Distinct().Count() > 1;
}
}
}
Here is a type extension you can call directly from your list. The pros of this code is to be adaptable to any type implementing IEquals and not only string + kick to use from your code.
The code :
public static class Tools
{
public static bool fDistinctProductType(this List<BasketOrderLine> lstToAnalyse)
{
BasketOrderLine ProductTypeA = lstToAnalyse.FirstOrDefault();
if (ProductTypeA == null) // It's null when lstToAnalyse is empty
return false;
BasketOrderLine ProductTypeB = lstToAnalyse.Where(b => b.ProductType.Equals(ProductTypeA.ProductType)).FirstOrDefault();
if (ProductTypeB == null) // It's null when it doesn't exists a distinct ProductType
return false;
return true;
}
}
How to call:
List<BasketOrderLine> lst = new List<BasketOrderLine>();
// Add element to list
if (lst.fDistinctProductType())
{
// DO Something
}
I have two variables that contain true/false data. THe first variable can be null but the second variable is always non null. Both variables will always be the same length.
var AnswerGridCorrect = "000111"; // or null
var AnswerGridResponses = "000011";
How could I change this data into an object oriented form. I already created classes and these are below. Here's is what I need the output to look like when converted to JSON:
"answers":[ // Json conversion made Answers into answers
{"correct":null,"response":true},
{"correct":null,"response":true},
{"correct":null,"response":true},
{"correct":null,"response":false}
}
Note that I am using LINQ to output the data so I think what I need is a function with parameters something like this:
.Select((t, index) => new {
Answer = t.Answer,
Answers = makeAnswer(t.AnswerGridCorrect,
t.AnswerGridResponses)
});
I am not sure if this helps but here were the classes I was using when I did this from JSON:
public class AnswerRow
{
public bool? Correct { get; set; }
public bool Response { get; set; }
}
public class AnswerRowList
{
public IList<AnswerRow> AnswerRows { get; set; }
}
Here is an implementation for your makeAnswers method:
public List<AnswerRow> makeAnswers(string c, string r)
{
var result = new List<AnswerRow>();
for(var i=0; i<r.Length; i++)
{
result.Add(
new AnswerRow {
Correct = c!=null?new Nullable<bool>(c[i]=='1'):null,
Response = r[i]=='1'
});
}
return result;
}
Rene's answer is probably correct, but here's the (unnecessarily complex) Linq way:
AnswerRowList MakeAnswer(string answerGridCorrect, string answerGridResponses)
{
return new AnswerRowList()
{
AnswerRows = answerGridResponses.Zip(
answerGridCorrect == null ?
Enumerable.Repeat<bool?>(null, answerGridResponses.Length) :
answerGridCorrect.Select(x => new Nullable<bool>(x == '1')),
(r, c) => new AnswerRow()
{
Correct = c,
Response = r == '1'
}).ToList()
};
}
I have a base class called BaseStatus which looks like this:
public class BaseStatus
{
public int UnitId { get; protected set; }
public UInt16 StatusValue { get; protected set; }
public string StatusCode { get; protected set; }
public string StatusDescription { get; protected set; }
public BaseStatus()
{
this.UnitId = -1;
this.StatusValue = 0;
this.StatusCode = null;
this.StatusDescription = null;
}
}
Furthermore i have two or more other base classes which derive from BaseStatus and define a other unit id. For example the two classes
public class BaseGlobalStatus : BaseStatus
{
public BaseGlobalStatus()
{
base.UnitId = -1;
}
}
public class BaseGcmGdmStatus : BaseStatus
{
public BaseGcmGdmStatus()
{
base.UnitId = 2;
}
}
public class BaseCcuStatus : BaseStatus
{
public BaseCcuStatus()
{
base.UnitId = 1;
}
}
The Background is that i want to derive from for example BaseCcuStatus and have the correct UnitId in the derived class.
Now i define my correct status classes for example:
public class StatStErrDefinition : BaseGlobalStatus
{
public StatStErrDefinition()
: base()
{
base.StatusDescription = "Kommando nicht zulässig, unit im state ERROR";
base.StatusCode = "STAT_ST_ERR";
base.StatusValue = 3;
}
}
public class GcmStErrDefinition : BaseGcmGdmStatus
{
public GcmStErrDefinition()
: base()
{
base.StatusDescription = "Kommando nicht zulässig, unit im state ERROR";
base.StatusCode = "STAT_ST_ERR";
base.StatusValue = 3;
}
}
public class CcuStErrDefinition : BaseCcuStatus
{
public CcuStErrDefinition()
: base()
{
base.StatusDescription = "Kommando nicht zulässig, unit im state ERROR";
base.StatusCode = "STAT_ST_ERR";
base.StatusValue = 3;
}
}
For my understading, the three classes StatStErrDefinition, GcmStErrDefinition and CcuStErrDefinition should have the UnitId which is set in the derived BaseClass?
Now that i have defined my three Status Classes i want to get them into a registry. Currently im using this piece of code to try get them. Problem is that the result has no items.
registry = new StatusDictionary<UInt16, BaseStatus>();
var unitStatus = typeof(BaseStatus)
.Assembly.GetTypes()
.Where(x => x.BaseType == typeof(BaseStatus))
.Select(x => new
{
StatusType = x,
UnitId = x.GetProperty("UnitId", BindingFlags.Public)
StatVal = x.GetProperty("StatusValue", BindingFlags.Public)
}
)
.Where(x => x.StatVal != null && x.UnitId != null)
.Select(x => new
{
UnitId = (int)x.UnitId.GetValue(null, null),
StatusValue = (UInt16)x.StatVal.GetValue(null, null),
Factory = (Func<BaseStatus>)(() => ((BaseStatus)Activator.CreateInstance(x.StatusType)))
});
try
{
foreach (var status in unitStatus)
{
if (status.UnitId == unitId
|| status.UnitId < 0)
registry.Register(status.StatusValue, status.Factory);
}
}
catch (Exception ex)
{
string temp = ex.Message;
}
After the LINQ expression the var unitStatus is empty...
Later, the registry call looks like that to get the specific class but that is unimportant at this point:
stat = StatusContainer.GetRegistry(this.unitTypeId).GetInstance(this.StatusValue);
For information:
I want to get the status class which should be in the registry by the unittypeid and the specific status value.
Currently my registry method does not work because he is not able to find any class. So there has to be a mistake somewhere. Thanks in advance
#Update 1
I changed my functionality a little bit:
registry = new StatusDictionary<UInt16, BaseStatus>();
//get all types of cucrent assembly
var allAssemblyTypes = Assembly.GetCallingAssembly().GetTypes();
//get all types from base status
var baseStatusTypes = allAssemblyTypes.Where(x => x.BaseType == typeof(BaseStatus));
//Place all concrete types in the foundtypes
List<Type> foundTypes = new List<Type>();
foreach (Type item in baseStatusTypes)
{
var temp = allAssemblyTypes.Where(x => x.BaseType == item)
.Select(x => new
{
StatusType = x,
UnitId = x.GetProperty("UnitId", BindingFlags.Public),
StatVal = x.GetProperty("StatusValue", BindingFlags.Public),
}
);
}
Temp contains now the correct type.
Problem is that if temp is type of StatStErrDefinition the StatusValue and UnitId Property is null.
The fact is that these members are instance members. Is there a way to get the values out of them?
First thing first : your LINQ query is pretty long.
divide it in different step and store them in different variables (or make properties out of them, whatever you prefer)
This is
easy to read / maintain
easy to debug
With this given I think you are able to solve your problem :)
To check if the class is of a certain type you could use the method .OfType
Use this method to get the value. Notice that you must make an instance in your case because the value change in your constructor.
public static object GetPropValue(Type src, string propName)
{
var prop = src.GetProperty(propName);
var instance = Activator.CreateInstance(src);
var value = prop.GetValue(instance);
return value;
}
Instead of
UnitId = x.GetProperty("UnitId", BindingFlags.Public),
use
UnitId = GetPropValue(x,"UnitId"),
I have a reflection method finds all the types in a namespace:
var models =
Assembly.GetAssembly(application).GetTypes().Where(
#t => #t.Namespace == typeof(ViewModelNamespaceBeacon).Namespace).OrderBy(#m => #m.Name).ToList();
My problem is I'm returning an Anonymous type with the name of:
{Name = "<>c__DisplayClass2" FullName = "UCHC.CFAR.Web.Models.FieldSecurityViewModel+<>c__DisplayClass2"}
Now from what I've seen detecting anonymous types are difficult( 1141874 ) but I can always filter "funky" names, ie .Contains("<>c_ ") so thats not a big deal.
I'm just trying to find this anonymous type so I can refactor it away. The namespace I'm inspecting is my ViewModel namespace and should be free of too much logic. Now given I've just said that I do have one ViewModel which does perform some logic ( is a mid-refactoring of a couple of other helper classes ) and seems to be identified by name in the name of my anonymous type:
public List<string> Roles { get; private set; }
public IEnumerable<SelectListItem> ViewModelSelectList { get; private set; }
public List<SecurityRule> SecurityRules { get; set; }
public Type SelectedViewModel { get; set; }
public FieldSecurityViewModel(IEnumerable<string> roles,
IEnumerable<Type> viewModels,
string selectedViewModelName = ""
)
{
SetFilteredRoles(roles);
SetViewModelSelectList(viewModels, selectedViewModelName);
}
private void SetViewModelSelectList(IEnumerable<Type> viewModels, string selectedViewModelName)
{
ViewModelSelectList = from v in viewModels
select new SelectListItem()
{
Selected = v.Name == selectedViewModelName,
Text = GenerateFriendlyViewModelName(v.Name),
Value = v.Name
};
return;
}
private void SetFilteredRoles(IEnumerable<string> roles)
{
Roles = roles.Where(#a => !#a.EndsWith("Admin") && !#a.EndsWith("NonFacultyUsers") && #a.StartsWith("CFAR.")).ToList();
}
public static string GenerateFriendlyViewModelName(string typeName)
{
var result = typeName.Replace("ViewModel", "")
.Replace("GridViewModel", "")
.Replace("EditViewModel", "")
.Replace("GridModel", "");
return result.HumanizeCamel();
}
public IEnumerable<ModelMetadata> GetProperties()
{
if (SelectedViewModel == null)
return new List<ModelMetadata>();
var properties = ModelMetadataProviders.Current.GetMetadataForType(null, SelectedViewModel).Properties;
return properties.Where(#p => !#p.PropertyName.EndsWith("PK_ID") && !#p.PropertyName.StartsWith("FK_") && !#p.PropertyName.EndsWith("_PK"));
}
I just can't find the anon type in there.
A "...DisplayClass" is usually associated with an anonymous method that needs to capture variables.
In this case, I'm betting on the lambda expression associated with the "select new SelectListItem()", since you're referring to the parameter to the method.
Try commenting out the contents of the SetViewModelSelectList method, and see if the anonymous type disappears.