Finding an Anonymous Type's Source - c#

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.

Related

C# Change selected object from a list without changing the original list

Here I've selected the record which a want to get into a new variable. and after that, when I'm changing the value of 'itm.note' it's automatically modifying the original list (Obj.Testlist) as well. How can this be avoided? Only want to change 'itm' object and Obj.Testlist list should be keep as it is.
var itm = Obj.Testlist.Where(x => x.id == 1).SingleOrDefault();
itm.note = "text";
You could clone the fetched item, but that wouldn't be efficient.
How about this:
var changedFetchedItem = Obj.Testlist.Where(x => x.id == 1)
.Select(x => new
{
Id = 1,
Note = "text",
// copy the other properties that you plan to use
// don't copy the ones that you don't use.
}
.SingleOrDefault();
Since you will be fetching at utmost one item, this is very efficient.
I chose to create an object with anonymous type. If you need a specific type, you can add the type after the keyword new
Since I have large model, decided to use cloning for this (Sample code),
public class TestClone : ICloneable
{
public bool IsSuccess { get; set; }
public string Note { get; set; }
public string ErrorDetail { get; set; }
public object Clone()
{
return this.MemberwiseClone();
}
}
static void Main(string[] args)
{
var test1 = new TestClone() { IsSuccess = true, Note= "text", ErrorDetail = "DTL1" };
var test2 = (TestClone) test1.Clone();
test2.Note= "new text";
}

Filtering nested lists with nullable property

Say I have the following class structures
public class EmailActivity {
public IEnumerable<MemberActivity> Activity { get; set; }
public string EmailAddress { get; set; }
}
public class MemberActivity {
public EmailAction? Action { get; set; }
public string Type { get; set; }
}
public enum EmailAction {
None = 0,
Open = 1,
Click = 2,
Bounce = 3
}
I wish to filter a list of EmailActivity objects based on the presence of a MemberActivity with a non-null EmailAction matching a provided list of EmailAction matches. I want to return just the EmailAddress property as a List<string>.
This is as far as I've got
List<EmailAction> activityTypes; // [ EmailAction.Open, EmailAction.Bounce ]
List<string> activityEmailAddresses =
emailActivity.Where(
member => member.Activity.Where(
activity => activityTypes.Contains(activity.Action)
)
)
.Select(member => member.EmailAddress)
.ToList();
However I get an error message "CS1503 Argument 1: cannot convert from 'EmailAction?' to 'EmailAction'"
If then modify activityTypes to allow null values List<EmailAction?> I get the following "CS1662 Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type".
The issue is the nested .Where it's returning a list, but the parent .Where requires a bool result. How would I tackle this problem?
I realise I could do with with nested loops however I'm trying to brush up my C# skills!
Using List.Contains is not ideal in terms of performance, HashSet is a better option, also if you want to select the email address as soon as it contains one of the searched actions, you can use Any:
var activityTypes = new HashSet<EmailAction>() { EmailAction.Open, EmailAction.Bounce };
List<string> activityEmailAddresses =
emailActivity.Where(
member => member.Activity.Any(
activity => activity.Action.HasValue &&
activityTypes.Contains(activity.Action.Value)
)
)
.Select(activity => activity.EmailAddress)
.ToList();
You want to use All or Any depends if you want each or at least one match...
HashSet<EmailAction> activityTypes = new HashSet<EmailAction> { EmailAction.None };
var emailActivity = new List<EmailActivity>
{
new EmailActivity { Activity = new List<MemberActivity>{ new MemberActivity { Action = EmailAction.None } }, EmailAddress = "a" },
new EmailActivity { Activity = new List<MemberActivity>{ new MemberActivity { Action = EmailAction.Click } }, EmailAddress = "b" }
};
// Example with Any but All can be used as well
var activityEmailAddresses = emailActivity
.Where(x => x.Activity.Any(_ => _.Action.HasValue && activityTypes.Contains(_.Action.Value)))
.Select(x => x.EmailAddress)
.ToArray();
// Result is [ "a" ]

Check which elements are on one list comparing to another list LINQ

I have two lists, one of all languages and another subset of languages that the site has, the idea is to return all the languages but change the property of a boolean if the element of the subset corresponds to the list of all languages.
DTO of language:
public class DTOLanguage
{
public bool HaveLanguage { get; set; }
public int IdLanguage { get; set; }
//Other properties...
}
Method that returns all languages:
public List<DTOLanguage> GetLanguages()
{
var result = repository.RepSite.GetLanguages().Select(x => new DTOLanguage
{
IdLanguage = x.IdLanguage,
CodName = x.CodName,
Name = x.Name
}).ToList();
return result;
}
Method that returns the subset of languages:
public List<DTOLanguage> GetLanguagesById(int idSite)
{
var result = repository.RepSite.GetLanguagesById(idSite).Select(x => new DTOLanguage
{
IdLanguage = x.IdLanguage
}).ToList();
return result;
}
The GetLanguagesById is called in the DataAccess layer, so what Im thinking is that this method should receive another parameter (what GetLanguages returns) and make some fancy LINQ there.
I know that I can filter (example):
SubsetOfLanguages.Where(lg => lg.IdLanguage == AllLanguagesItem.IdLanguage)
{
AllLanguagesItem.HaveLanguage = True;
}
But Im not really sure as how it should be.
Thanks in advance.
You could use Contains extension method this way:
var languages=GetLanguages();
var subsetids=repository.RepSite.GetLanguagesById(idSite).Select(x =>x.IdLanguage);//Select just the id value
foreach(var l in languages.Where(l=>subsetids.Contains(l.IdLanguage)))
{
l.HaveLanguage = true;
}
You could do this:
var allLanguages = GetLanguages();
var subset = SubsetOfLanguages
.Where(lg => allLanguages.Any(a => lg.IdLanguage == a.IdLanguage))
.ToArray();
foreach(var item in subset)
{
item.HaveLanguage = True;
}

Custom generic DTO Assembler

I'm trying to create a method which can be used like this:
Assembler.CreateTransfer(i);
i is an item inside a dynamic collection.
i is a domain object.
CreateTransfer() should return an instance of i type + Transfer (if my domain object is User, then it should return an instance of UserTransfer.
As for my models is like this:
public abstract class UserBase {
public long UserId { get; set; }
public string Username { get; set; }
}
public class UserTransfer : UserBase, ITransferObject { }
public partial class User : UserTransfer, IModelBase, IDomainObject {
public User() {
Roles = new List<Role>();
}
public virtual ICollection<Role> Roles { get; set; }
}
So far, I've accomplished this:
public static TTransfer CreateTransfer<TTransfer, TDomain>(TDomain d)
where TTransfer : ITransferObject
where TDomain : IDomainObject
{ ... }
This works, because I know the type of TTransfer and TDomain.
And I can call it like: CreateTransfer<UserTransfer, User>(d).
The problem comes when I try create the dto without specifying any type:
CreateTransfer(d);
Of course I've added an overload for this task and I hope I can magically accomplish the following:
public static ITransferObject CreateTransfer(IDomainObject d) {
// do magic
return CreateTransfer<transfer, domain>(d);
}
But in the real world, this is as far as I could get:
public static ITransferObject CreateTransfer(IDomainObject d) {
var dType = d.GetType();
var assemblyName = dType.Assembly.FullName;
var domainName = dType.FullName;
var transferName = domainName + "Transfer";
var domain = Activator.CreateInstance(assemblyName, domainName).UnWrap();
var transfer = Activator.CreateInstance(assemblyName, transferName).UnWrap();
return CreateTransfer< ?, ?>(d); // Problem
}
Both domain and transfer objects are being created correctly.
The main question is: Is there any way to be able to call CreateTransfer<domain, transfer>(d)? Any help will be appreciated.
You can use reflection to call the generic method.
Something like this:
var method = typeof(ClassThatDefinesCreateTransfer)
.GetMethods()
.Single(x => x.Name == "CreateTransfer" &&
x.IsGenericMethodDefinition)
.MakeGenericMethod(dType, transferType);
return (ITransferObject )method.Invoke(null, new object[] { d });
You probably want to cache at least the result of typeof(ClassThatDefinesCreateTransfer).GetMethods().

Replace a collection item using Linq

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.

Categories